From 815abf0fea01d596bf05eaebc0ca83ab0c3bf539 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 6 May 2020 17:23:42 +0900 Subject: [PATCH 1/2] Fix #7362: autodoc: does not render correct signatures for built-in functions --- CHANGES | 1 + sphinx/ext/autodoc/__init__.py | 4 ---- tests/test_ext_autodoc.py | 26 ++++++++++++++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index 200bd0887..b8b630a0b 100644 --- a/CHANGES +++ b/CHANGES @@ -87,6 +87,7 @@ Bugs fixed autodoc_typehints='description' mode * #7551: autodoc: failed to import nested class * #7637: autodoc: system defined TypeVars are shown in Python 3.9 +* #7362: autodoc: does not render correct signatures for built-in functions * #7551: autosummary: a nested class is indexed as non-nested class * #7535: sphinx-autogen: crashes when custom template uses inheritance * #7536: sphinx-autogen: crashes when template uses i18n feature diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 8bf2e82a2..b90841004 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -1052,10 +1052,6 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ kwargs.setdefault('show_annotation', False) unwrapped = inspect.unwrap(self.object) - if ((inspect.isbuiltin(unwrapped) or inspect.ismethoddescriptor(unwrapped)) and - not inspect.is_cython_function_or_method(unwrapped)): - # cannot introspect arguments of a C function or method - return None try: self.env.app.emit('autodoc-before-process-signature', unwrapped, False) sig = inspect.signature(unwrapped) diff --git a/tests/test_ext_autodoc.py b/tests/test_ext_autodoc.py index 4833daa8b..e6e32b604 100644 --- a/tests/test_ext_autodoc.py +++ b/tests/test_ext_autodoc.py @@ -1190,6 +1190,32 @@ def test_autofunction_for_method(app): ] +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autofunction_for_builtin(app): + actual = do_autodoc(app, 'function', 'os.umask') + assert list(actual) == [ + '', + '.. py:function:: umask(mask, /)', + ' :module: os', + '', + ' Set the current numeric umask and return the previous umask.', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autofunction_for_methoddescriptor(app): + actual = do_autodoc(app, 'function', 'builtins.int.__add__') + assert list(actual) == [ + '', + '.. py:function:: int.__add__(self, value, /)', + ' :module: builtins', + '', + ' Return self+value.', + '', + ] + + def test_abstractmethods(app): options = {"members": None, "undoc-members": None} From 92e0007179e958d56c030867f2dd006485b1c69d Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 6 May 2020 17:32:49 +0900 Subject: [PATCH 2/2] Fix autodoc: does not render correct signatures for built-in methods --- sphinx/ext/autodoc/__init__.py | 28 +++++++++++++++++----------- tests/test_ext_autodoc.py | 17 +++++++++++++++-- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index b90841004..2af450a08 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -1464,17 +1464,23 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: kwargs.setdefault('show_annotation', False) unwrapped = inspect.unwrap(self.object) - if ((inspect.isbuiltin(unwrapped) or inspect.ismethoddescriptor(unwrapped)) and - not inspect.is_cython_function_or_method(unwrapped)): - # can never get arguments of a C function or method - return None - if inspect.isstaticmethod(unwrapped, cls=self.parent, name=self.object_name): - self.env.app.emit('autodoc-before-process-signature', unwrapped, False) - sig = inspect.signature(unwrapped, bound_method=False) - else: - self.env.app.emit('autodoc-before-process-signature', unwrapped, True) - sig = inspect.signature(unwrapped, bound_method=True) - args = stringify_signature(sig, **kwargs) + try: + if self.object == object.__init__ and self.parent != object: + # Classes not having own __init__() method are shown as no arguments. + # + # Note: The signature of object.__init__() is (self, /, *args, **kwargs). + # But it makes users confused. + args = '()' + else: + if inspect.isstaticmethod(unwrapped, cls=self.parent, name=self.object_name): + self.env.app.emit('autodoc-before-process-signature', unwrapped, False) + sig = inspect.signature(unwrapped, bound_method=False) + else: + self.env.app.emit('autodoc-before-process-signature', unwrapped, True) + sig = inspect.signature(unwrapped, bound_method=True) + args = stringify_signature(sig, **kwargs) + except ValueError: + args = '' if self.env.config.strip_signature_backslash: # escape backslashes for reST diff --git a/tests/test_ext_autodoc.py b/tests/test_ext_autodoc.py index e6e32b604..8fe0c60ba 100644 --- a/tests/test_ext_autodoc.py +++ b/tests/test_ext_autodoc.py @@ -573,8 +573,8 @@ def test_autodoc_inherited_members_None(app): # check methods for object class are shown actual = do_autodoc(app, 'class', 'target.inheritance.Derived', options) - assert ' .. py:method:: Derived.__init__' in actual - assert ' .. py:method:: Derived.__str__' in actual + assert ' .. py:method:: Derived.__init__()' in actual + assert ' .. py:method:: Derived.__str__()' in actual @pytest.mark.sphinx('html', testroot='ext-autodoc') @@ -1216,6 +1216,19 @@ def test_autofunction_for_methoddescriptor(app): ] +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_automethod_for_builtin(app): + actual = do_autodoc(app, 'method', 'builtins.int.__add__') + assert list(actual) == [ + '', + '.. py:method:: int.__add__(value, /)', + ' :module: builtins', + '', + ' Return self+value.', + '', + ] + + def test_abstractmethods(app): options = {"members": None, "undoc-members": None}