Merge pull request #9799 from tk0miya/9781_autodoc_preserve_hexadecimal

Fix #9781: autodoc_preserve_defaults does not support hexadecimal
This commit is contained in:
Takeshi KOMIYA
2021-11-01 00:58:33 +09:00
committed by GitHub
4 changed files with 47 additions and 9 deletions

View File

@@ -71,6 +71,8 @@ Bugs fixed
* #9756: autodoc: Crashed if classmethod does not have __func__ attribute * #9756: autodoc: Crashed if classmethod does not have __func__ attribute
* #9757: autodoc: :confval:`autodoc_inherit_docstrings` does not effect to * #9757: autodoc: :confval:`autodoc_inherit_docstrings` does not effect to
overriden classmethods overriden classmethods
* #9781: autodoc: :confval:`autodoc_preserve_defaults` does not support
hexadecimal numeric
* #9630: autosummary: Failed to build summary table if :confval:`primary_domain` * #9630: autosummary: Failed to build summary table if :confval:`primary_domain`
is not 'py' is not 'py'
* #9670: html: Fix download file with special characters * #9670: html: Fix download file with special characters

View File

@@ -11,7 +11,8 @@
import ast import ast
import inspect import inspect
from typing import Any, Dict import sys
from typing import Any, Dict, List, Optional
from sphinx.application import Sphinx from sphinx.application import Sphinx
from sphinx.locale import __ from sphinx.locale import __
@@ -49,11 +50,32 @@ def get_function_def(obj: Any) -> ast.FunctionDef:
return None return None
def get_default_value(lines: List[str], position: ast.AST) -> Optional[str]:
try:
if sys.version_info < (3, 8): # only for py38+
return None
elif position.lineno == position.end_lineno:
line = lines[position.lineno - 1]
return line[position.col_offset:position.end_col_offset]
else:
# multiline value is not supported now
return None
except (AttributeError, IndexError):
return None
def update_defvalue(app: Sphinx, obj: Any, bound_method: bool) -> None: def update_defvalue(app: Sphinx, obj: Any, bound_method: bool) -> None:
"""Update defvalue info of *obj* using type_comments.""" """Update defvalue info of *obj* using type_comments."""
if not app.config.autodoc_preserve_defaults: if not app.config.autodoc_preserve_defaults:
return return
try:
lines = inspect.getsource(obj).splitlines()
if lines[0].startswith((' ', r'\t')):
lines.insert(0, '') # insert a dummy line to follow what get_function_def() does.
except OSError:
lines = []
try: try:
function = get_function_def(obj) function = get_function_def(obj)
if function.args.defaults or function.args.kw_defaults: if function.args.defaults or function.args.kw_defaults:
@@ -64,11 +86,17 @@ def update_defvalue(app: Sphinx, obj: Any, bound_method: bool) -> None:
for i, param in enumerate(parameters): for i, param in enumerate(parameters):
if param.default is not param.empty: if param.default is not param.empty:
if param.kind in (param.POSITIONAL_ONLY, param.POSITIONAL_OR_KEYWORD): if param.kind in (param.POSITIONAL_ONLY, param.POSITIONAL_OR_KEYWORD):
value = DefaultValue(ast_unparse(defaults.pop(0))) # type: ignore default = defaults.pop(0)
parameters[i] = param.replace(default=value) value = get_default_value(lines, default)
if value is None:
value = ast_unparse(default) # type: ignore
parameters[i] = param.replace(default=DefaultValue(value))
else: else:
value = DefaultValue(ast_unparse(kw_defaults.pop(0))) # type: ignore default = kw_defaults.pop(0)
parameters[i] = param.replace(default=value) value = get_default_value(lines, default)
if value is None:
value = ast_unparse(default) # type: ignore
parameters[i] = param.replace(default=DefaultValue(value))
sig = sig.replace(parameters=parameters) sig = sig.replace(parameters=parameters)
obj.__signature__ = sig obj.__signature__ = sig
except (AttributeError, TypeError): except (AttributeError, TypeError):

View File

@@ -7,7 +7,8 @@ SENTINEL = object()
def foo(name: str = CONSTANT, def foo(name: str = CONSTANT,
sentinel: Any = SENTINEL, sentinel: Any = SENTINEL,
now: datetime = datetime.now()) -> None: now: datetime = datetime.now(),
color: int = 0xFFFFFF) -> None:
"""docstring""" """docstring"""
@@ -15,5 +16,5 @@ class Class:
"""docstring""" """docstring"""
def meth(self, name: str = CONSTANT, sentinel: Any = SENTINEL, def meth(self, name: str = CONSTANT, sentinel: Any = SENTINEL,
now: datetime = datetime.now()) -> None: now: datetime = datetime.now(), color: int = 0xFFFFFF) -> None:
"""docstring""" """docstring"""

View File

@@ -8,6 +8,8 @@
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
import sys
import pytest import pytest
from .test_ext_autodoc import do_autodoc from .test_ext_autodoc import do_autodoc
@@ -16,6 +18,11 @@ from .test_ext_autodoc import do_autodoc
@pytest.mark.sphinx('html', testroot='ext-autodoc', @pytest.mark.sphinx('html', testroot='ext-autodoc',
confoverrides={'autodoc_preserve_defaults': True}) confoverrides={'autodoc_preserve_defaults': True})
def test_preserve_defaults(app): def test_preserve_defaults(app):
if sys.version_info < (3, 8):
color = "16777215"
else:
color = "0xFFFFFF"
options = {"members": None} options = {"members": None}
actual = do_autodoc(app, 'module', 'target.preserve_defaults', options) actual = do_autodoc(app, 'module', 'target.preserve_defaults', options)
assert list(actual) == [ assert list(actual) == [
@@ -30,14 +37,14 @@ def test_preserve_defaults(app):
'', '',
'', '',
' .. py:method:: Class.meth(name: str = CONSTANT, sentinel: Any = SENTINEL, ' ' .. py:method:: Class.meth(name: str = CONSTANT, sentinel: Any = SENTINEL, '
'now: datetime.datetime = datetime.now()) -> None', 'now: datetime.datetime = datetime.now(), color: int = %s) -> None' % color,
' :module: target.preserve_defaults', ' :module: target.preserve_defaults',
'', '',
' docstring', ' docstring',
'', '',
'', '',
'.. py:function:: foo(name: str = CONSTANT, sentinel: Any = SENTINEL, now: ' '.. py:function:: foo(name: str = CONSTANT, sentinel: Any = SENTINEL, now: '
'datetime.datetime = datetime.now()) -> None', 'datetime.datetime = datetime.now(), color: int = %s) -> None' % color,
' :module: target.preserve_defaults', ' :module: target.preserve_defaults',
'', '',
' docstring', ' docstring',