Merge pull request #7355 from tk0miya/7331_cyfunction

Fix #7331: autodoc: a cython-function are not recognized as a function
This commit is contained in:
Takeshi KOMIYA 2020-03-22 23:21:47 +09:00 committed by GitHub
commit 0fb7b8f525
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 67 additions and 2 deletions

View File

@ -132,6 +132,7 @@ Bugs fixed
* #7267: autodoc: error message for invalid directive options has wrong location * #7267: autodoc: error message for invalid directive options has wrong location
* #7329: autodoc: info-field-list is wrongly generated from type hints into the * #7329: autodoc: info-field-list is wrongly generated from type hints into the
class description even if ``autoclass_content='class'`` set class description even if ``autoclass_content='class'`` set
* #7331: autodoc: a cython-function is not recognized as a function
* #5637: inheritance_diagram: Incorrect handling of nested class names * #5637: inheritance_diagram: Incorrect handling of nested class names
* #7139: ``code-block:: guess`` does not work * #7139: ``code-block:: guess`` does not work
* #7325: html: source_suffix containing dot leads to wrong source link * #7325: html: source_suffix containing dot leads to wrong source link

View File

@ -52,6 +52,7 @@ extras_require = {
'pytest-cov', 'pytest-cov',
'html5lib', 'html5lib',
'typed_ast', # for py35-37 'typed_ast', # for py35-37
'cython',
], ],
} }

View File

@ -1011,7 +1011,8 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
if self.env.config.autodoc_typehints in ('none', 'description'): if self.env.config.autodoc_typehints in ('none', 'description'):
kwargs.setdefault('show_annotation', False) kwargs.setdefault('show_annotation', False)
if inspect.isbuiltin(self.object) or inspect.ismethoddescriptor(self.object): if ((inspect.isbuiltin(self.object) or inspect.ismethoddescriptor(self.object)) and
not inspect.is_cython_function_or_method(self.object)):
# cannot introspect arguments of a C function or method # cannot introspect arguments of a C function or method
return None return None
try: try:
@ -1430,7 +1431,8 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
if self.env.config.autodoc_typehints == 'none': if self.env.config.autodoc_typehints == 'none':
kwargs.setdefault('show_annotation', False) kwargs.setdefault('show_annotation', False)
if inspect.isbuiltin(self.object) or inspect.ismethoddescriptor(self.object): if ((inspect.isbuiltin(self.object) or inspect.ismethoddescriptor(self.object)) and
not inspect.is_cython_function_or_method(self.object)):
# can never get arguments of a C function or method # can never get arguments of a C function or method
return None return None
if inspect.isstaticmethod(self.object, cls=self.parent, name=self.object_name): if inspect.isstaticmethod(self.object, cls=self.parent, name=self.object_name):

View File

@ -197,6 +197,14 @@ def isabstractmethod(obj: Any) -> bool:
return safe_getattr(obj, '__isabstractmethod__', False) is True return safe_getattr(obj, '__isabstractmethod__', False) is True
def is_cython_function_or_method(obj: Any) -> bool:
"""Check if the object is a function or method in cython."""
try:
return obj.__class__.__name__ == 'cython_function_or_method'
except AttributeError:
return False
def isattributedescriptor(obj: Any) -> bool: def isattributedescriptor(obj: Any) -> bool:
"""Check if the object is an attribute like descriptor.""" """Check if the object is an attribute like descriptor."""
if inspect.isdatadescriptor(object): if inspect.isdatadescriptor(object):
@ -207,6 +215,9 @@ def isattributedescriptor(obj: Any) -> bool:
if isfunction(obj) or isbuiltin(obj) or inspect.ismethod(obj): if isfunction(obj) or isbuiltin(obj) or inspect.ismethod(obj):
# attribute must not be either function, builtin and method # attribute must not be either function, builtin and method
return False return False
elif is_cython_function_or_method(obj):
# attribute must not be either function and method (for cython)
return False
elif inspect.isclass(obj): elif inspect.isclass(obj):
# attribute must not be a class # attribute must not be a class
return False return False

View File

@ -0,0 +1,12 @@
# cython: binding=True
def foo(*args, **kwargs):
"""Docstring."""
class Class:
"""Docstring."""
def meth(self, name: str, age: int = 0) -> None:
"""Docstring."""
pass

View File

@ -22,6 +22,13 @@ from sphinx.testing.util import SphinxTestApp, Struct # NOQA
from sphinx.util import logging from sphinx.util import logging
from sphinx.util.docutils import LoggingReporter from sphinx.util.docutils import LoggingReporter
try:
# Enable pyximport to test cython module
import pyximport
pyximport.install()
except ImportError:
pyximport = None
app = None app = None
@ -1609,3 +1616,34 @@ def test_singledispatchmethod():
' A method for general use.', ' A method for general use.',
'', '',
] ]
@pytest.mark.usefixtures('setup_test')
@pytest.mark.skipif(pyximport is None, reason='cython is not installed')
def test_cython():
options = {"members": None,
"undoc-members": None}
actual = do_autodoc(app, 'module', 'target.cython', options)
assert list(actual) == [
'',
'.. py:module:: target.cython',
'',
'',
'.. py:class:: Class',
' :module: target.cython',
'',
' Docstring.',
'',
'',
' .. py:method:: Class.meth(name: str, age: int = 0) -> None',
' :module: target.cython',
'',
' Docstring.',
'',
'',
'.. py:function:: foo(*args, **kwargs)',
' :module: target.cython',
'',
' Docstring.',
'',
]