Merge pull request #7031 from tk0miya/7023_nested_partial_functions_not_listed

#7023: autodoc: nested partial functions are not listed
This commit is contained in:
Takeshi KOMIYA 2020-01-19 15:49:52 +09:00 committed by GitHub
commit a1f6bbf800
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 40 additions and 12 deletions

View File

@ -51,6 +51,7 @@ Bugs fixed
* #6559: Wrong node-ids are generated in glossary directive * #6559: Wrong node-ids are generated in glossary directive
* #6986: apidoc: misdetects module name for .so file inside module * #6986: apidoc: misdetects module name for .so file inside module
* #6999: napoleon: fails to parse tilde in :exc: role * #6999: napoleon: fails to parse tilde in :exc: role
* #7023: autodoc: nested partial functions are not listed
Testing Testing
-------- --------

View File

@ -121,6 +121,17 @@ def isenumattribute(x: Any) -> bool:
return isinstance(x, enum.Enum) return isinstance(x, enum.Enum)
def unpartial(obj: Any) -> Any:
"""Get an original object from partial object.
This returns given object itself if not partial.
"""
while ispartial(obj):
obj = obj.func
return obj
def ispartial(obj: Any) -> bool: def ispartial(obj: Any) -> bool:
"""Check if the object is partial.""" """Check if the object is partial."""
return isinstance(obj, (partial, partialmethod)) return isinstance(obj, (partial, partialmethod))
@ -197,24 +208,21 @@ def isattributedescriptor(obj: Any) -> bool:
def isfunction(obj: Any) -> bool: def isfunction(obj: Any) -> bool:
"""Check if the object is function.""" """Check if the object is function."""
return inspect.isfunction(obj) or ispartial(obj) and inspect.isfunction(obj.func) return inspect.isfunction(unpartial(obj))
def isbuiltin(obj: Any) -> bool: def isbuiltin(obj: Any) -> bool:
"""Check if the object is builtin.""" """Check if the object is builtin."""
return inspect.isbuiltin(obj) or ispartial(obj) and inspect.isbuiltin(obj.func) return inspect.isbuiltin(unpartial(obj))
def iscoroutinefunction(obj: Any) -> bool: def iscoroutinefunction(obj: Any) -> bool:
"""Check if the object is coroutine-function.""" """Check if the object is coroutine-function."""
obj = unpartial(obj)
if hasattr(obj, '__code__') and inspect.iscoroutinefunction(obj): if hasattr(obj, '__code__') and inspect.iscoroutinefunction(obj):
# check obj.__code__ because iscoroutinefunction() crashes for custom method-like # check obj.__code__ because iscoroutinefunction() crashes for custom method-like
# objects (see https://github.com/sphinx-doc/sphinx/issues/6605) # objects (see https://github.com/sphinx-doc/sphinx/issues/6605)
return True return True
elif (ispartial(obj) and hasattr(obj.func, '__code__') and
inspect.iscoroutinefunction(obj.func)):
# partialed
return True
else: else:
return False return False

View File

@ -1,11 +1,12 @@
from functools import partial from functools import partial
def func1(): def func1(a, b, c):
"""docstring of func1""" """docstring of func1"""
pass pass
func2 = partial(func1) func2 = partial(func1, 1)
func3 = partial(func1) func3 = partial(func2, 2)
func3.__doc__ = "docstring of func3" func3.__doc__ = "docstring of func3"
func4 = partial(func3, 3)

View File

@ -1241,19 +1241,25 @@ def test_partialfunction():
'.. py:module:: target.partialfunction', '.. py:module:: target.partialfunction',
'', '',
'', '',
'.. py:function:: func1()', '.. py:function:: func1(a, b, c)',
' :module: target.partialfunction', ' :module: target.partialfunction',
'', '',
' docstring of func1', ' docstring of func1',
' ', ' ',
'', '',
'.. py:function:: func2()', '.. py:function:: func2(b, c)',
' :module: target.partialfunction', ' :module: target.partialfunction',
'', '',
' docstring of func1', ' docstring of func1',
' ', ' ',
'', '',
'.. py:function:: func3()', '.. py:function:: func3(c)',
' :module: target.partialfunction',
'',
' docstring of func3',
' ',
'',
'.. py:function:: func4()',
' :module: target.partialfunction', ' :module: target.partialfunction',
'', '',
' docstring of func3', ' docstring of func3',

View File

@ -511,3 +511,15 @@ def test_isproperty(app):
assert inspect.isproperty(Base.meth) is False # method of class assert inspect.isproperty(Base.meth) is False # method of class
assert inspect.isproperty(Base().meth) is False # method of instance assert inspect.isproperty(Base().meth) is False # method of instance
assert inspect.isproperty(func) is False # function assert inspect.isproperty(func) is False # function
def test_unpartial():
def func1(a, b, c):
pass
func2 = functools.partial(func1, 1)
func2.__doc__ = "func2"
func3 = functools.partial(func2, 2) # nested partial object
assert inspect.unpartial(func2) is func1
assert inspect.unpartial(func3) is func1