Skip to content

Commit 506590d

Browse files
authored
Merge pull request sphinx-doc#9640 from tk0miya/9639_support_asyncgenfunction
Close sphinx-doc#9639: autodoc: Support asynchronous generator functions
2 parents bebd6bd + ccfca45 commit 506590d

File tree

8 files changed

+91
-56
lines changed

8 files changed

+91
-56
lines changed

CHANGES

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ Deprecated
1313
Features added
1414
--------------
1515

16+
* #9639: autodoc: Support asynchronous generator functions
17+
1618
Bugs fixed
1719
----------
1820

sphinx/ext/autodoc/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1318,7 +1318,7 @@ def add_directive_header(self, sig: str) -> None:
13181318
sourcename = self.get_sourcename()
13191319
super().add_directive_header(sig)
13201320

1321-
if inspect.iscoroutinefunction(self.object):
1321+
if inspect.iscoroutinefunction(self.object) or inspect.isasyncgenfunction(self.object):
13221322
self.add_line(' :async:', sourcename)
13231323

13241324
def format_signature(self, **kwargs: Any) -> str:
@@ -2137,7 +2137,7 @@ def add_directive_header(self, sig: str) -> None:
21372137
obj = self.parent.__dict__.get(self.object_name, self.object)
21382138
if inspect.isabstractmethod(obj):
21392139
self.add_line(' :abstractmethod:', sourcename)
2140-
if inspect.iscoroutinefunction(obj):
2140+
if inspect.iscoroutinefunction(obj) or inspect.isasyncgenfunction(obj):
21412141
self.add_line(' :async:', sourcename)
21422142
if inspect.isclassmethod(obj):
21432143
self.add_line(' :classmethod:', sourcename)

sphinx/util/inspect.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
import warnings
2020
from functools import partial, partialmethod
2121
from importlib import import_module
22-
from inspect import Parameter, isclass, ismethod, ismethoddescriptor, ismodule # NOQA
22+
from inspect import (Parameter, isasyncgenfunction, isclass, ismethod, # NOQA
23+
ismethoddescriptor, ismodule)
2324
from io import StringIO
2425
from types import ModuleType
2526
from typing import Any, Callable, Dict, Mapping, Optional, Sequence, Tuple, Type, cast

tests/roots/test-ext-autodoc/target/coroutine.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ async def do_coroutine3():
1717
"""A documented coroutine staticmethod"""
1818
pass
1919

20+
async def do_asyncgen(self):
21+
"""A documented async generator"""
22+
yield
23+
2024

2125
async def _other_coro_func():
2226
return "run"

tests/roots/test-ext-autodoc/target/functions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ def func():
88
async def coroutinefunc():
99
pass
1010

11+
12+
async def asyncgenerator():
13+
yield
14+
1115
partial_func = partial(func)
1216
partial_coroutinefunc = partial(coroutinefunc)
1317

tests/test_ext_autodoc.py

Lines changed: 0 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1619,59 +1619,6 @@ def test_bound_method(app):
16191619
]
16201620

16211621

1622-
@pytest.mark.sphinx('html', testroot='ext-autodoc')
1623-
def test_coroutine(app):
1624-
actual = do_autodoc(app, 'function', 'target.functions.coroutinefunc')
1625-
assert list(actual) == [
1626-
'',
1627-
'.. py:function:: coroutinefunc()',
1628-
' :module: target.functions',
1629-
' :async:',
1630-
'',
1631-
]
1632-
1633-
options = {"members": None}
1634-
actual = do_autodoc(app, 'class', 'target.coroutine.AsyncClass', options)
1635-
assert list(actual) == [
1636-
'',
1637-
'.. py:class:: AsyncClass()',
1638-
' :module: target.coroutine',
1639-
'',
1640-
'',
1641-
' .. py:method:: AsyncClass.do_coroutine()',
1642-
' :module: target.coroutine',
1643-
' :async:',
1644-
'',
1645-
' A documented coroutine function',
1646-
'',
1647-
'',
1648-
' .. py:method:: AsyncClass.do_coroutine2()',
1649-
' :module: target.coroutine',
1650-
' :async:',
1651-
' :classmethod:',
1652-
'',
1653-
' A documented coroutine classmethod',
1654-
'',
1655-
'',
1656-
' .. py:method:: AsyncClass.do_coroutine3()',
1657-
' :module: target.coroutine',
1658-
' :async:',
1659-
' :staticmethod:',
1660-
'',
1661-
' A documented coroutine staticmethod',
1662-
'',
1663-
]
1664-
1665-
# force-synchronized wrapper
1666-
actual = do_autodoc(app, 'function', 'target.coroutine.sync_func')
1667-
assert list(actual) == [
1668-
'',
1669-
'.. py:function:: sync_func()',
1670-
' :module: target.coroutine',
1671-
'',
1672-
]
1673-
1674-
16751622
@pytest.mark.sphinx('html', testroot='ext-autodoc')
16761623
def test_partialmethod(app):
16771624
expected = [

tests/test_ext_autodoc_autoclass.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,3 +389,45 @@ def test_class_alias_having_doccomment(app):
389389
' docstring',
390390
'',
391391
]
392+
393+
394+
@pytest.mark.sphinx('html', testroot='ext-autodoc')
395+
def test_coroutine(app):
396+
options = {"members": None}
397+
actual = do_autodoc(app, 'class', 'target.coroutine.AsyncClass', options)
398+
assert list(actual) == [
399+
'',
400+
'.. py:class:: AsyncClass()',
401+
' :module: target.coroutine',
402+
'',
403+
'',
404+
' .. py:method:: AsyncClass.do_asyncgen()',
405+
' :module: target.coroutine',
406+
' :async:',
407+
'',
408+
' A documented async generator',
409+
'',
410+
'',
411+
' .. py:method:: AsyncClass.do_coroutine()',
412+
' :module: target.coroutine',
413+
' :async:',
414+
'',
415+
' A documented coroutine function',
416+
'',
417+
'',
418+
' .. py:method:: AsyncClass.do_coroutine2()',
419+
' :module: target.coroutine',
420+
' :async:',
421+
' :classmethod:',
422+
'',
423+
' A documented coroutine classmethod',
424+
'',
425+
'',
426+
' .. py:method:: AsyncClass.do_coroutine3()',
427+
' :module: target.coroutine',
428+
' :async:',
429+
' :staticmethod:',
430+
'',
431+
' A documented coroutine staticmethod',
432+
'',
433+
]

tests/test_ext_autodoc_autofunction.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,38 @@ def test_wrapped_function_contextmanager(app):
168168
" You'll feel better in this context!",
169169
'',
170170
]
171+
172+
173+
@pytest.mark.sphinx('html', testroot='ext-autodoc')
174+
def test_coroutine(app):
175+
actual = do_autodoc(app, 'function', 'target.functions.coroutinefunc')
176+
assert list(actual) == [
177+
'',
178+
'.. py:function:: coroutinefunc()',
179+
' :module: target.functions',
180+
' :async:',
181+
'',
182+
]
183+
184+
185+
@pytest.mark.sphinx('html', testroot='ext-autodoc')
186+
def test_synchronized_coroutine(app):
187+
actual = do_autodoc(app, 'function', 'target.coroutine.sync_func')
188+
assert list(actual) == [
189+
'',
190+
'.. py:function:: sync_func()',
191+
' :module: target.coroutine',
192+
'',
193+
]
194+
195+
196+
@pytest.mark.sphinx('html', testroot='ext-autodoc')
197+
def test_async_generator(app):
198+
actual = do_autodoc(app, 'function', 'target.functions.asyncgenerator')
199+
assert list(actual) == [
200+
'',
201+
'.. py:function:: asyncgenerator()',
202+
' :module: target.functions',
203+
' :async:',
204+
'',
205+
]

0 commit comments

Comments
 (0)