Fix #7559: autodoc: misdetects a sync function is async

This commit is contained in:
Takeshi KOMIYA 2020-04-28 01:02:00 +09:00
parent 5460ad6925
commit 25fc47e6b7
4 changed files with 31 additions and 3 deletions

View File

@ -74,6 +74,7 @@ Bugs fixed
* #6588: autodoc: Decorated inherited method has no documentation * #6588: autodoc: Decorated inherited method has no documentation
* #7469: autodoc: The change of autodoc-process-docstring for variables is * #7469: autodoc: The change of autodoc-process-docstring for variables is
cached unexpectedly cached unexpectedly
* #7559: autodoc: misdetects a sync function is async
* #7535: sphinx-autogen: crashes when custom template uses inheritance * #7535: sphinx-autogen: crashes when custom template uses inheritance
* #7536: sphinx-autogen: crashes when template uses i18n feature * #7536: sphinx-autogen: crashes when template uses i18n feature
* #2785: html: Bad alignment of equation links * #2785: html: Bad alignment of equation links

View File

@ -125,13 +125,15 @@ def unwrap(obj: Any) -> Any:
return obj return obj
def unwrap_all(obj: Any) -> Any: def unwrap_all(obj: Any, *, stop: Callable = None) -> Any:
""" """
Get an original object from wrapped object (unwrapping partials, wrapped Get an original object from wrapped object (unwrapping partials, wrapped
functions, and other decorators). functions, and other decorators).
""" """
while True: while True:
if ispartial(obj): if stop and stop(obj):
return obj
elif ispartial(obj):
obj = obj.func obj = obj.func
elif inspect.isroutine(obj) and hasattr(obj, '__wrapped__'): elif inspect.isroutine(obj) and hasattr(obj, '__wrapped__'):
obj = obj.__wrapped__ obj = obj.__wrapped__
@ -287,7 +289,8 @@ def isroutine(obj: Any) -> bool:
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 = unwrap_all(obj) # unwrap staticmethod, classmethod and partial (except wrappers)
obj = unwrap_all(obj, stop=lambda o: hasattr(o, '__wrapped__'))
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)

View File

@ -1,3 +1,7 @@
import asyncio
from functools import wraps
class AsyncClass: class AsyncClass:
async def do_coroutine(self): async def do_coroutine(self):
"""A documented coroutine function""" """A documented coroutine function"""
@ -16,3 +20,14 @@ class AsyncClass:
async def _other_coro_func(): async def _other_coro_func():
return "run" return "run"
def myawait(f):
@wraps(f)
def wrapper(*args, **kwargs):
awaitable = f(*args, **kwargs)
return asyncio.run(awaitable)
return wrapper
sync_func = myawait(_other_coro_func)

View File

@ -1379,6 +1379,15 @@ def test_coroutine():
'', '',
] ]
# force-synchronized wrapper
actual = do_autodoc(app, 'function', 'target.coroutine.sync_func')
assert list(actual) == [
'',
'.. py:function:: sync_func()',
' :module: target.coroutine',
'',
]
@pytest.mark.sphinx('html', testroot='ext-autodoc') @pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_partialmethod(app): def test_partialmethod(app):