diff --git a/CHANGES b/CHANGES index 099068d6d..f3bfb09d7 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 f30051a6c..80bcc0e8d 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) @@ -1452,17 +1448,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 53d1c35ab..4d313c174 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') @@ -1217,6 +1217,45 @@ 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.', + '', + ] + + +@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}