diff --git a/CHANGES b/CHANGES index 5f8c8821a4..55c0a833e5 100644 --- a/CHANGES +++ b/CHANGES @@ -7,9 +7,14 @@ Dependencies Incompatible changes -------------------- +* #8105: autodoc: the signature of class constructor will be shown for decorated + classes, not a signature of decorator + Deprecated ---------- +* The ``follow_wrapped`` argument of ``sphinx.util.inspect.signature()`` + Features added -------------- @@ -22,6 +27,8 @@ Bugs fixed * #7613: autodoc: autodoc does not respect __signature__ of the class * #4606: autodoc: the location of the warning is incorrect for inherited method +* #8105: autodoc: the signature of class constructor is incorrect if the class + is decorated Testing -------- diff --git a/doc/extdev/deprecated.rst b/doc/extdev/deprecated.rst index 2bb8aebfd6..797648a1ac 100644 --- a/doc/extdev/deprecated.rst +++ b/doc/extdev/deprecated.rst @@ -26,6 +26,12 @@ The following is a list of deprecated interfaces. - (will be) Removed - Alternatives + + * - The ``follow_wrapped`` argument of ``sphinx.util.inspect.signature()`` + - 3.4 + - 5.0 + - N/A + * - ``sphinx.builders.latex.LaTeXBuilder.usepackages`` - 3.3 - 5.0 diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 66bd2c69b7..92b3ad3e71 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -1222,7 +1222,7 @@ def format_args(self, **kwargs: Any) -> str: try: self.env.app.emit('autodoc-before-process-signature', self.object, False) - sig = inspect.signature(self.object, follow_wrapped=True, + sig = inspect.signature(self.object, type_aliases=self.env.config.autodoc_type_aliases) args = stringify_signature(sig, **kwargs) except TypeError as exc: @@ -1862,7 +1862,6 @@ def format_args(self, **kwargs: Any) -> str: else: self.env.app.emit('autodoc-before-process-signature', self.object, True) sig = inspect.signature(self.object, bound_method=True, - follow_wrapped=True, type_aliases=self.env.config.autodoc_type_aliases) args = stringify_signature(sig, **kwargs) except TypeError as exc: diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py index 66eac1c61a..27f478675e 100644 --- a/sphinx/util/inspect.py +++ b/sphinx/util/inspect.py @@ -431,14 +431,20 @@ def _should_unwrap(subject: Callable) -> bool: return False -def signature(subject: Callable, bound_method: bool = False, follow_wrapped: bool = False, +def signature(subject: Callable, bound_method: bool = False, follow_wrapped: bool = None, type_aliases: Dict = {}) -> inspect.Signature: """Return a Signature object for the given *subject*. :param bound_method: Specify *subject* is a bound method or not :param follow_wrapped: Same as ``inspect.signature()``. - Defaults to ``False`` (get a signature of *subject*). """ + + if follow_wrapped is None: + follow_wrapped = True + else: + warnings.warn('The follow_wrapped argument of sphinx.util.inspect.signature() is ' + 'deprecated', RemovedInSphinx50Warning, stacklevel=2) + try: try: if _should_unwrap(subject): diff --git a/tests/roots/test-ext-autodoc/target/decorator.py b/tests/roots/test-ext-autodoc/target/decorator.py index 61398b324e..faad3fff95 100644 --- a/tests/roots/test-ext-autodoc/target/decorator.py +++ b/tests/roots/test-ext-autodoc/target/decorator.py @@ -29,3 +29,25 @@ class Bar: @deco1 def meth(self, name=None, age=None): pass + + +class Baz: + @deco1 + def __init__(self, name=None, age=None): + pass + + +class Qux: + @deco1 + def __new__(self, name=None, age=None): + pass + + +class _Metaclass(type): + @deco1 + def __call__(self, name=None, age=None): + pass + + +class Quux(metaclass=_Metaclass): + pass diff --git a/tests/test_ext_autodoc_autoclass.py b/tests/test_ext_autodoc_autoclass.py index 89a79c2c7c..76f01f5b36 100644 --- a/tests/test_ext_autodoc_autoclass.py +++ b/tests/test_ext_autodoc_autoclass.py @@ -48,3 +48,28 @@ def test_classes(app): '', ] + +def test_decorators(app): + actual = do_autodoc(app, 'class', 'target.decorator.Baz') + assert list(actual) == [ + '', + '.. py:class:: Baz(name=None, age=None)', + ' :module: target.decorator', + '', + ] + + actual = do_autodoc(app, 'class', 'target.decorator.Qux') + assert list(actual) == [ + '', + '.. py:class:: Qux(name=None, age=None)', + ' :module: target.decorator', + '', + ] + + actual = do_autodoc(app, 'class', 'target.decorator.Quux') + assert list(actual) == [ + '', + '.. py:class:: Quux(name=None, age=None)', + ' :module: target.decorator', + '', + ] diff --git a/tests/test_util_inspect.py b/tests/test_util_inspect.py index c21eaaa167..204fa65b7e 100644 --- a/tests/test_util_inspect.py +++ b/tests/test_util_inspect.py @@ -100,7 +100,7 @@ def wrapped_bound_method(*args, **kwargs): # wrapped bound method sig = inspect.signature(wrapped_bound_method) - assert stringify_signature(sig) == '(*args, **kwargs)' + assert stringify_signature(sig) == '(arg1, **kwargs)' def test_signature_partialmethod():