Merge pull request #10451 from tk0miya/9648_autodoc_typehints_description_and_stared_args

Fix #9648: autodoc: *args and **kwargs entries are duplicated
This commit is contained in:
Takeshi KOMIYA
2022-05-22 13:47:07 +09:00
committed by GitHub
10 changed files with 120 additions and 14 deletions

View File

@@ -39,6 +39,8 @@ Bugs fixed
* #9575: autodoc: The annotation of return value should not be shown when
``autodoc_typehints="description"``
* #9648: autodoc: ``*args`` and ``**kwargs`` entries are duplicated when
``autodoc_typehints="description"``
* #10456: py domain: ``:meta:`` fields are displayed if docstring contains two
or more meta-field

View File

@@ -115,7 +115,15 @@ def modify_field_list(node: nodes.field_list, annotations: Dict[str, str],
if name == 'return':
continue
arg = arguments.get(name, {})
if '*' + name in arguments:
name = '*' + name
arguments.get(name)
elif '**' + name in arguments:
name = '**' + name
arguments.get(name)
else:
arg = arguments.get(name, {})
if not arg.get('type'):
field = nodes.field()
field += nodes.field_name('', 'type ' + name)
@@ -167,13 +175,19 @@ def augment_descriptions_with_types(
has_type.add('return')
# Add 'type' for parameters with a description but no declared type.
for name in annotations:
for name, annotation in annotations.items():
if name in ('return', 'returns'):
continue
if '*' + name in has_description:
name = '*' + name
elif '**' + name in has_description:
name = '**' + name
if name in has_description and name not in has_type:
field = nodes.field()
field += nodes.field_name('', 'type ' + name)
field += nodes.field_body('', nodes.paragraph('', annotations[name]))
field += nodes.field_body('', nodes.paragraph('', annotation))
node += field
# Add 'rtype' if 'return' is present and 'rtype' isn't.

View File

@@ -94,8 +94,10 @@ def missing_attr(c,
class _ClassWithDocumentedInit:
"""Class docstring."""
def __init__(self, x: int) -> None:
def __init__(self, x: int, *args: int, **kwargs: int) -> None:
"""Init docstring.
:param x: Some integer
:param args: Some integer
:param kwargs: Some integer
"""

View File

@@ -0,0 +1,5 @@
import os
import sys
sys.path.insert(0, os.path.abspath('.'))
extensions = ['sphinx.ext.napoleon']

View File

@@ -0,0 +1,6 @@
test-ext-napoleon
=================
.. toctree::
typehints

View File

@@ -0,0 +1,11 @@
def hello(x: int, *args: int, **kwargs: int) -> None:
"""
Parameters
----------
x
X
*args
Additional arguments.
**kwargs
Extra arguments.
"""

View File

@@ -0,0 +1,5 @@
typehints
=========
.. automodule:: mypackage.typehints
:members:

View File

@@ -1034,19 +1034,27 @@ def test_autodoc_typehints_description_with_documented_init(app):
)
app.build()
context = (app.outdir / 'index.txt').read_text(encoding='utf8')
assert ('class target.typehints._ClassWithDocumentedInit(x)\n'
assert ('class target.typehints._ClassWithDocumentedInit(x, *args, **kwargs)\n'
'\n'
' Class docstring.\n'
'\n'
' Parameters:\n'
' **x** (*int*) --\n'
' * **x** (*int*) --\n'
'\n'
' __init__(x)\n'
' * **args** (*int*) --\n'
'\n'
' * **kwargs** (*int*) --\n'
'\n'
' __init__(x, *args, **kwargs)\n'
'\n'
' Init docstring.\n'
'\n'
' Parameters:\n'
' **x** (*int*) -- Some integer\n'
' * **x** (*int*) -- Some integer\n'
'\n'
' * **args** (*int*) -- Some integer\n'
'\n'
' * **kwargs** (*int*) -- Some integer\n'
'\n'
' Return type:\n'
' None\n' == context)
@@ -1063,16 +1071,20 @@ def test_autodoc_typehints_description_with_documented_init_no_undoc(app):
)
app.build()
context = (app.outdir / 'index.txt').read_text(encoding='utf8')
assert ('class target.typehints._ClassWithDocumentedInit(x)\n'
assert ('class target.typehints._ClassWithDocumentedInit(x, *args, **kwargs)\n'
'\n'
' Class docstring.\n'
'\n'
' __init__(x)\n'
' __init__(x, *args, **kwargs)\n'
'\n'
' Init docstring.\n'
'\n'
' Parameters:\n'
' **x** (*int*) -- Some integer\n' == context)
' * **x** (*int*) -- Some integer\n'
'\n'
' * **args** (*int*) -- Some integer\n'
'\n'
' * **kwargs** (*int*) -- Some integer\n' == context)
@pytest.mark.sphinx('text', testroot='ext-autodoc',
@@ -1089,16 +1101,20 @@ def test_autodoc_typehints_description_with_documented_init_no_undoc_doc_rtype(a
)
app.build()
context = (app.outdir / 'index.txt').read_text(encoding='utf8')
assert ('class target.typehints._ClassWithDocumentedInit(x)\n'
assert ('class target.typehints._ClassWithDocumentedInit(x, *args, **kwargs)\n'
'\n'
' Class docstring.\n'
'\n'
' __init__(x)\n'
' __init__(x, *args, **kwargs)\n'
'\n'
' Init docstring.\n'
'\n'
' Parameters:\n'
' **x** (*int*) -- Some integer\n' == context)
' * **x** (*int*) -- Some integer\n'
'\n'
' * **args** (*int*) -- Some integer\n'
'\n'
' * **kwargs** (*int*) -- Some integer\n' == context)
@pytest.mark.sphinx('text', testroot='ext-autodoc',

View File

@@ -2593,3 +2593,48 @@ Sample class with PEP 526 annotations and numpy docstring
"""
print(actual)
assert expected == actual
@pytest.mark.sphinx('text', testroot='ext-napoleon',
confoverrides={'autodoc_typehints': 'description',
'autodoc_typehints_description_target': 'all'})
def test_napoleon_and_autodoc_typehints_description_all(app, status, warning):
app.build()
content = (app.outdir / 'typehints.txt').read_text(encoding='utf-8')
assert content == (
'typehints\n'
'*********\n'
'\n'
'mypackage.typehints.hello(x, *args, **kwargs)\n'
'\n'
' Parameters:\n'
' * **x** (*int*) -- X\n'
'\n'
' * ***args** (*int*) -- Additional arguments.\n'
'\n'
' * ****kwargs** (*int*) -- Extra arguments.\n'
'\n'
' Return type:\n'
' None\n'
)
@pytest.mark.sphinx('text', testroot='ext-napoleon',
confoverrides={'autodoc_typehints': 'description',
'autodoc_typehints_description_target': 'documented_params'})
def test_napoleon_and_autodoc_typehints_description_documented_params(app, status, warning):
app.build()
content = (app.outdir / 'typehints.txt').read_text(encoding='utf-8')
assert content == (
'typehints\n'
'*********\n'
'\n'
'mypackage.typehints.hello(x, *args, **kwargs)\n'
'\n'
' Parameters:\n'
' * **x** (*int*) -- X\n'
'\n'
' * ***args** (*int*) -- Additional arguments.\n'
'\n'
' * ****kwargs** (*int*) -- Extra arguments.\n'
)