summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakeshi KOMIYA <i.tkomiya@gmail.com>2020-04-28 01:02:00 +0900
committerTakeshi KOMIYA <i.tkomiya@gmail.com>2020-05-01 22:05:45 +0900
commit25fc47e6b7890aec22b2c24e68e7febfaee848e0 (patch)
treee13193b4088815bccb8c2166cdb5a8908d2e8e0d
parent5460ad6925199b57b27b7d059825d3560872edbb (diff)
downloadsphinx-git-25fc47e6b7890aec22b2c24e68e7febfaee848e0.tar.gz
Fix #7559: autodoc: misdetects a sync function is async
-rw-r--r--CHANGES1
-rw-r--r--sphinx/util/inspect.py9
-rw-r--r--tests/roots/test-ext-autodoc/target/coroutine.py15
-rw-r--r--tests/test_autodoc.py9
4 files changed, 31 insertions, 3 deletions
diff --git a/CHANGES b/CHANGES
index 44be3fbf9..3942c4240 100644
--- a/CHANGES
+++ b/CHANGES
@@ -74,6 +74,7 @@ Bugs fixed
* #6588: autodoc: Decorated inherited method has no documentation
* #7469: autodoc: The change of autodoc-process-docstring for variables is
cached unexpectedly
+* #7559: autodoc: misdetects a sync function is async
* #7535: sphinx-autogen: crashes when custom template uses inheritance
* #7536: sphinx-autogen: crashes when template uses i18n feature
* #2785: html: Bad alignment of equation links
diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py
index 38777728a..9eb05b29b 100644
--- a/sphinx/util/inspect.py
+++ b/sphinx/util/inspect.py
@@ -125,13 +125,15 @@ def unwrap(obj: Any) -> Any:
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
functions, and other decorators).
"""
while True:
- if ispartial(obj):
+ if stop and stop(obj):
+ return obj
+ elif ispartial(obj):
obj = obj.func
elif inspect.isroutine(obj) and hasattr(obj, '__wrapped__'):
obj = obj.__wrapped__
@@ -287,7 +289,8 @@ def isroutine(obj: Any) -> bool:
def iscoroutinefunction(obj: Any) -> bool:
"""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):
# check obj.__code__ because iscoroutinefunction() crashes for custom method-like
# objects (see https://github.com/sphinx-doc/sphinx/issues/6605)
diff --git a/tests/roots/test-ext-autodoc/target/coroutine.py b/tests/roots/test-ext-autodoc/target/coroutine.py
index 69602325d..692dd4883 100644
--- a/tests/roots/test-ext-autodoc/target/coroutine.py
+++ b/tests/roots/test-ext-autodoc/target/coroutine.py
@@ -1,3 +1,7 @@
+import asyncio
+from functools import wraps
+
+
class AsyncClass:
async def do_coroutine(self):
"""A documented coroutine function"""
@@ -16,3 +20,14 @@ class AsyncClass:
async def _other_coro_func():
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)
diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py
index cbbdbb787..6d57d795d 100644
--- a/tests/test_autodoc.py
+++ b/tests/test_autodoc.py
@@ -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')
def test_partialmethod(app):