Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #8105: Fix bug where autodoc generates incorrect signature for decorated class #8115

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions sphinx/ext/autodoc/__init__.py
Expand Up @@ -1378,7 +1378,7 @@ def get_user_defined_function_or_method(obj: Any, attr: str) -> Any:
if call is not None:
self.env.app.emit('autodoc-before-process-signature', call, True)
try:
sig = inspect.signature(call, bound_method=True)
sig = inspect.signature(call, bound_method=True, follow_wrapped=True)
return type(self.object), '__call__', sig
except ValueError:
pass
Expand All @@ -1388,7 +1388,7 @@ def get_user_defined_function_or_method(obj: Any, attr: str) -> Any:
if new is not None:
self.env.app.emit('autodoc-before-process-signature', new, True)
try:
sig = inspect.signature(new, bound_method=True)
sig = inspect.signature(new, bound_method=True, follow_wrapped=True)
return self.object, '__new__', sig
except ValueError:
pass
Expand All @@ -1398,7 +1398,7 @@ def get_user_defined_function_or_method(obj: Any, attr: str) -> Any:
if init is not None:
self.env.app.emit('autodoc-before-process-signature', init, True)
try:
sig = inspect.signature(init, bound_method=True)
sig = inspect.signature(init, bound_method=True, follow_wrapped=True)
return self.object, '__init__', sig
except ValueError:
pass
Expand Down
2 changes: 1 addition & 1 deletion sphinx/ext/autodoc/type_comment.py
Expand Up @@ -119,7 +119,7 @@ def update_annotations_using_type_comments(app: Sphinx, obj: Any, bound_method:
try:
type_sig = get_type_comment(obj, bound_method)
if type_sig:
sig = inspect.signature(obj, bound_method)
sig = inspect.signature(obj, bound_method, follow_wrapped=True)
for param in sig.parameters.values():
if param.name not in obj.__annotations__:
annotation = type_sig.parameters[param.name].annotation
Expand Down
18 changes: 18 additions & 0 deletions tests/roots/test-ext-autodoc/target/decorator.py
Expand Up @@ -29,3 +29,21 @@ class Bar:
@deco1
def meth(self, name=None, age=None):
pass


class BarCall:
@deco1
def __call__(self, name=None, age=None):
pass


class BarNew:
@deco1
def __new__(cls, name=None, age=None):
pass


class BarInit:
@deco1
def __init__(self, name=None, age=None):
pass
33 changes: 33 additions & 0 deletions tests/test_ext_autodoc.py
Expand Up @@ -1286,6 +1286,39 @@ def test_automethod_for_decorated(app):
]


@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autoclass_for_decorated_call(app):
actual = do_autodoc(app, 'class', 'target.decorator.BarCall')
assert list(actual) == [
'',
'.. py:class:: BarCall(name=None, age=None)',
' :module: target.decorator',
'',
]


@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autoclass_for_decorated_new(app):
actual = do_autodoc(app, 'class', 'target.decorator.BarNew')
assert list(actual) == [
'',
'.. py:class:: BarNew(name=None, age=None)',
' :module: target.decorator',
'',
]


@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autoclass_for_decorated_init(app):
actual = do_autodoc(app, 'class', 'target.decorator.BarInit')
assert list(actual) == [
'',
'.. py:class:: BarInit(name=None, age=None)',
' :module: target.decorator',
'',
]


@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_abstractmethods(app):
options = {"members": None,
Expand Down