|
37 | 37 | UNINITIALIZED_ATTR, |
38 | 38 | ) |
39 | 39 | from sphinx.ext.autodoc.mock import ismock, mock, undecorate |
40 | | -from sphinx.ext.autodoc.type_comment import update_annotations_using_type_comments |
| 40 | +from sphinx.ext.autodoc.preserve_defaults import update_default_value |
| 41 | +from sphinx.ext.autodoc.type_comment import _update_annotations_using_type_comments |
| 42 | +from sphinx.ext.autodoc.typehints import _record_typehints |
41 | 43 | from sphinx.locale import __ |
42 | 44 | from sphinx.pycode import ModuleAnalyzer |
43 | 45 | from sphinx.util import inspect, logging |
@@ -694,9 +696,9 @@ def _load_object_by_name( |
694 | 696 | else: |
695 | 697 | func = None |
696 | 698 | if func is not None: |
697 | | - app = SimpleNamespace(config=config) |
698 | 699 | # update the annotations of the property getter |
699 | | - update_annotations_using_type_comments(app, func, False) # type: ignore[arg-type] |
| 700 | + if config.autodoc_use_type_comments: |
| 701 | + _update_annotations_using_type_comments(func, False) |
700 | 702 |
|
701 | 703 | try: |
702 | 704 | signature = inspect.signature( |
@@ -909,6 +911,7 @@ def _load_object_by_name( |
909 | 911 | signatures = _format_signatures( |
910 | 912 | args=args, |
911 | 913 | retann=retann, |
| 914 | + autodoc_annotations=current_document.autodoc_annotations, |
912 | 915 | config=config, |
913 | 916 | docstrings=docstrings, |
914 | 917 | events=events, |
@@ -1170,6 +1173,7 @@ def _update_module_annotations_from_type_comments(mod: ModuleType) -> None: |
1170 | 1173 |
|
1171 | 1174 | def _format_signatures( |
1172 | 1175 | *, |
| 1176 | + autodoc_annotations: dict[str, dict[str, str]], |
1173 | 1177 | config: Config, |
1174 | 1178 | docstrings: list[list[str]] | None, |
1175 | 1179 | events: EventManager, |
@@ -1236,6 +1240,14 @@ def _format_signatures( |
1236 | 1240 | # Only keep the return annotation |
1237 | 1241 | signatures = [('', retann) for _args, retann in signatures] |
1238 | 1242 |
|
| 1243 | + _record_typehints( |
| 1244 | + autodoc_annotations=autodoc_annotations, |
| 1245 | + name=props.full_name, |
| 1246 | + obj=props._obj, |
| 1247 | + short_literals=config.python_display_short_literal_types, |
| 1248 | + type_aliases=config.autodoc_type_aliases, |
| 1249 | + typehints_format=config.autodoc_typehints_format, |
| 1250 | + ) |
1239 | 1251 | if result := events.emit_firstresult( |
1240 | 1252 | 'autodoc-process-signature', |
1241 | 1253 | props.obj_type, |
@@ -1303,6 +1315,7 @@ def _format_signatures( |
1303 | 1315 | properties=frozenset(), |
1304 | 1316 | ) |
1305 | 1317 | signatures += _format_signatures( |
| 1318 | + autodoc_annotations=autodoc_annotations, |
1306 | 1319 | config=config, |
1307 | 1320 | docstrings=None, |
1308 | 1321 | events=events, |
@@ -1414,6 +1427,7 @@ def _format_signatures( |
1414 | 1427 | properties=frozenset(), |
1415 | 1428 | ) |
1416 | 1429 | signatures += _format_signatures( |
| 1430 | + autodoc_annotations=autodoc_annotations, |
1417 | 1431 | config=config, |
1418 | 1432 | docstrings=None, |
1419 | 1433 | events=events, |
@@ -1538,8 +1552,10 @@ def _extract_signature_from_object( |
1538 | 1552 | events=events, |
1539 | 1553 | get_attr=get_attr, |
1540 | 1554 | parent=parent, |
| 1555 | + preserve_defaults=config.autodoc_preserve_defaults, |
1541 | 1556 | props=props, |
1542 | 1557 | type_aliases=config.autodoc_type_aliases, |
| 1558 | + use_type_comments=config.autodoc_use_type_comments, |
1543 | 1559 | ) |
1544 | 1560 | if sig is None: |
1545 | 1561 | return [] |
@@ -1584,38 +1600,75 @@ def _get_signature_object( |
1584 | 1600 | events: EventManager, |
1585 | 1601 | get_attr: _AttrGetter, |
1586 | 1602 | parent: Any, |
| 1603 | + preserve_defaults: bool, |
1587 | 1604 | props: _ItemProperties, |
1588 | 1605 | type_aliases: Mapping[str, str] | None, |
| 1606 | + use_type_comments: bool, |
1589 | 1607 | ) -> Signature | None: |
1590 | 1608 | """Return a Signature for *obj*, or None on failure.""" |
1591 | | - obj = props._obj |
1592 | | - if props.obj_type in {'function', 'decorator'}: |
1593 | | - events.emit('autodoc-before-process-signature', obj, False) |
| 1609 | + obj, is_bound_method = _get_object_for_signature( |
| 1610 | + props=props, get_attr=get_attr, parent=parent, type_aliases=type_aliases |
| 1611 | + ) |
| 1612 | + if obj is None or isinstance(obj, Signature): |
| 1613 | + return obj |
| 1614 | + |
| 1615 | + if preserve_defaults: |
| 1616 | + update_default_value(obj, bound_method=is_bound_method) |
| 1617 | + if use_type_comments: |
| 1618 | + _update_annotations_using_type_comments(obj, bound_method=is_bound_method) |
| 1619 | + events.emit('autodoc-before-process-signature', obj, is_bound_method) |
| 1620 | + |
| 1621 | + if props.obj_type in {'class', 'exception', 'function', 'method', 'decorator'}: |
1594 | 1622 | try: |
1595 | | - return inspect.signature(obj, type_aliases=type_aliases) |
| 1623 | + return inspect.signature( |
| 1624 | + obj, bound_method=is_bound_method, type_aliases=type_aliases |
| 1625 | + ) |
1596 | 1626 | except TypeError as exc: |
1597 | | - msg = __('Failed to get a function signature for %s: %s') |
| 1627 | + if props.obj_type in {'class', 'exception'}: |
| 1628 | + msg = __('Failed to get a constructor signature for %s: %s') |
| 1629 | + elif props.obj_type in {'function', 'decorator'}: |
| 1630 | + msg = __('Failed to get a function signature for %s: %s') |
| 1631 | + elif props.obj_type == 'method': |
| 1632 | + msg = __('Failed to get a method signature for %s: %s') |
| 1633 | + else: |
| 1634 | + msg = __('Failed to get a signature for %s: %s') |
1598 | 1635 | logger.warning(msg, props.full_name, exc) |
1599 | 1636 | return None |
1600 | 1637 | except ValueError: |
| 1638 | + # Still no signature: happens e.g. for old-style classes |
| 1639 | + # with __init__ in C and no `__text_signature__`. |
1601 | 1640 | return None |
1602 | 1641 |
|
| 1642 | + return None |
| 1643 | + |
| 1644 | + |
| 1645 | +def _get_object_for_signature( |
| 1646 | + props: _ItemProperties, |
| 1647 | + get_attr: _AttrGetter, |
| 1648 | + parent: Any, |
| 1649 | + type_aliases: Mapping[str, str] | None, |
| 1650 | +) -> tuple[Any, bool]: |
| 1651 | + """Return the object from which we will obtain the signature.""" |
| 1652 | + obj = props._obj |
| 1653 | + if props.obj_type in {'function', 'decorator'}: |
| 1654 | + return obj, False |
| 1655 | + |
1603 | 1656 | if props.obj_type in {'class', 'exception'}: |
1604 | 1657 | if isinstance(obj, (NewType, TypeVar)): |
1605 | 1658 | # Suppress signature |
1606 | | - return None |
| 1659 | + return None, False |
1607 | 1660 |
|
1608 | 1661 | try: |
1609 | 1662 | object_sig = obj.__signature__ |
1610 | 1663 | except AttributeError: |
1611 | 1664 | pass |
1612 | 1665 | else: |
1613 | 1666 | if isinstance(object_sig, Signature): |
1614 | | - return object_sig |
| 1667 | + return object_sig, False |
1615 | 1668 | if sys.version_info[:2] in {(3, 12), (3, 13)} and callable(object_sig): |
1616 | 1669 | # Support for enum.Enum.__signature__ in Python 3.12 |
1617 | 1670 | if isinstance(object_sig_str := object_sig(), str): |
1618 | | - return inspect.signature_from_str(object_sig_str) |
| 1671 | + return inspect.signature_from_str(object_sig_str), False |
1619 | 1672 |
|
1620 | 1673 | def get_user_defined_function_or_method(obj: Any, attr: str) -> Any: |
1621 | 1674 | """Get the `attr` function or method from `obj`, if it is user-defined.""" |
@@ -1643,72 +1696,40 @@ def get_user_defined_function_or_method(obj: Any, attr: str) -> Any: |
1643 | 1696 | if f'{meth.__module__}.{meth.__qualname__}' in blacklist: |
1644 | 1697 | continue |
1645 | 1698 |
|
1646 | | - events.emit('autodoc-before-process-signature', meth, True) |
1647 | 1699 | try: |
1648 | | - object_sig = inspect.signature( |
1649 | | - meth, |
1650 | | - bound_method=True, |
1651 | | - type_aliases=type_aliases, |
1652 | | - ) |
1653 | | - except TypeError as exc: |
1654 | | - msg = __('Failed to get a constructor signature for %s: %s') |
1655 | | - logger.warning(msg, props.full_name, exc) |
1656 | | - return None |
| 1700 | + inspect.signature(meth, bound_method=True, type_aliases=type_aliases) |
| 1701 | + except TypeError: |
| 1702 | + return meth, True # _get_signature_object() needs to log the failure |
1657 | 1703 | except ValueError: |
1658 | 1704 | continue |
1659 | 1705 | else: |
1660 | 1706 | from sphinx.ext.autodoc._property_types import _ClassDefProperties |
1661 | 1707 |
|
1662 | 1708 | assert isinstance(props, _ClassDefProperties) |
1663 | 1709 | props._signature_method_name = meth_name |
1664 | | - return object_sig |
| 1710 | + return meth, True |
1665 | 1711 |
|
1666 | 1712 | # None of the attributes are user-defined, so fall back to let inspect |
1667 | 1713 | # handle it. |
1668 | 1714 | # We don't know the exact method that inspect.signature will read |
1669 | | - # the signature from, so just pass the object itself to our hook. |
1670 | | - events.emit('autodoc-before-process-signature', obj, False) |
1671 | | - try: |
1672 | | - return inspect.signature( |
1673 | | - obj, |
1674 | | - bound_method=False, |
1675 | | - type_aliases=type_aliases, |
1676 | | - ) |
1677 | | - except TypeError as exc: |
1678 | | - msg = __('Failed to get a constructor signature for %s: %s') |
1679 | | - logger.warning(msg, props.full_name, exc) |
1680 | | - return None |
1681 | | - except ValueError: |
1682 | | - pass |
1683 | | - |
1684 | | - # Still no signature: happens e.g. for old-style classes |
1685 | | - # with __init__ in C and no `__text_signature__`. |
1686 | | - return None |
| 1715 | + # the signature from, so just return the object itself to be passed |
| 1716 | + # to the ``autodoc-before-process-signature`` hook. |
| 1717 | + return obj, False |
1687 | 1718 |
|
1688 | 1719 | if props.obj_type == 'method': |
1689 | 1720 | if obj == object.__init__ and parent != object: # NoQA: E721 |
1690 | 1721 | # Classes not having own __init__() method are shown as no arguments. |
1691 | 1722 | # |
1692 | 1723 | # Note: The signature of object.__init__() is (self, /, *args, **kwargs). |
1693 | 1724 | # But it makes users confused. |
1694 | | - return Signature() |
| 1725 | + return Signature(), False |
1695 | 1726 |
|
1696 | 1727 | is_bound_method = not inspect.isstaticmethod( |
1697 | 1728 | obj, cls=parent, name=props.object_name |
1698 | 1729 | ) |
1699 | | - events.emit('autodoc-before-process-signature', obj, is_bound_method) |
1700 | | - try: |
1701 | | - return inspect.signature( |
1702 | | - obj, bound_method=is_bound_method, type_aliases=type_aliases |
1703 | | - ) |
1704 | | - except TypeError as exc: |
1705 | | - msg = __('Failed to get a method signature for %s: %s') |
1706 | | - logger.warning(msg, props.full_name, exc) |
1707 | | - return None |
1708 | | - except ValueError: |
1709 | | - return None |
| 1730 | + return obj, is_bound_method |
1710 | 1731 |
|
1711 | | - return None |
| 1732 | + return None, False |
1712 | 1733 |
|
1713 | 1734 |
|
1714 | 1735 | def _annotate_to_first_argument( |
|
0 commit comments