summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakeshi KOMIYA <i.tkomiya@gmail.com>2021-11-01 00:58:33 +0900
committerGitHub <noreply@github.com>2021-11-01 00:58:33 +0900
commit1f91a0f8bd33eeffe082e31300f94df2ee10454f (patch)
tree06133666bfcfe4032f6ab951e0ec893d1983e1ac
parenta8eb1aab72a514b7257c780c0c57432732a702fb (diff)
parentb8844eb339df03b894a88b1eaf5859ebd443c792 (diff)
downloadsphinx-git-1f91a0f8bd33eeffe082e31300f94df2ee10454f.tar.gz
Merge pull request #9799 from tk0miya/9781_autodoc_preserve_hexadecimal
Fix #9781: autodoc_preserve_defaults does not support hexadecimal
-rw-r--r--CHANGES2
-rw-r--r--sphinx/ext/autodoc/preserve_defaults.py38
-rw-r--r--tests/roots/test-ext-autodoc/target/preserve_defaults.py5
-rw-r--r--tests/test_ext_autodoc_preserve_defaults.py11
4 files changed, 47 insertions, 9 deletions
diff --git a/CHANGES b/CHANGES
index bdd2fb152..33d20a45b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -71,6 +71,8 @@ Bugs fixed
* #9756: autodoc: Crashed if classmethod does not have __func__ attribute
* #9757: autodoc: :confval:`autodoc_inherit_docstrings` does not effect to
overriden classmethods
+* #9781: autodoc: :confval:`autodoc_preserve_defaults` does not support
+ hexadecimal numeric
* #9630: autosummary: Failed to build summary table if :confval:`primary_domain`
is not 'py'
* #9670: html: Fix download file with special characters
diff --git a/sphinx/ext/autodoc/preserve_defaults.py b/sphinx/ext/autodoc/preserve_defaults.py
index 3d859fe8e..d451d0973 100644
--- a/sphinx/ext/autodoc/preserve_defaults.py
+++ b/sphinx/ext/autodoc/preserve_defaults.py
@@ -11,7 +11,8 @@
import ast
import inspect
-from typing import Any, Dict
+import sys
+from typing import Any, Dict, List, Optional
from sphinx.application import Sphinx
from sphinx.locale import __
@@ -49,12 +50,33 @@ def get_function_def(obj: Any) -> ast.FunctionDef:
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:
"""Update defvalue info of *obj* using type_comments."""
if not app.config.autodoc_preserve_defaults:
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:
function = get_function_def(obj)
if function.args.defaults or function.args.kw_defaults:
sig = inspect.signature(obj)
@@ -64,11 +86,17 @@ def update_defvalue(app: Sphinx, obj: Any, bound_method: bool) -> None:
for i, param in enumerate(parameters):
if param.default is not param.empty:
if param.kind in (param.POSITIONAL_ONLY, param.POSITIONAL_OR_KEYWORD):
- value = DefaultValue(ast_unparse(defaults.pop(0))) # type: ignore
- parameters[i] = param.replace(default=value)
+ default = defaults.pop(0)
+ value = get_default_value(lines, default)
+ if value is None:
+ value = ast_unparse(default) # type: ignore
+ parameters[i] = param.replace(default=DefaultValue(value))
else:
- value = DefaultValue(ast_unparse(kw_defaults.pop(0))) # type: ignore
- parameters[i] = param.replace(default=value)
+ default = kw_defaults.pop(0)
+ 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)
obj.__signature__ = sig
except (AttributeError, TypeError):
diff --git a/tests/roots/test-ext-autodoc/target/preserve_defaults.py b/tests/roots/test-ext-autodoc/target/preserve_defaults.py
index 79305349b..422d41b95 100644
--- a/tests/roots/test-ext-autodoc/target/preserve_defaults.py
+++ b/tests/roots/test-ext-autodoc/target/preserve_defaults.py
@@ -7,7 +7,8 @@ SENTINEL = object()
def foo(name: str = CONSTANT,
sentinel: Any = SENTINEL,
- now: datetime = datetime.now()) -> None:
+ now: datetime = datetime.now(),
+ color: int = 0xFFFFFF) -> None:
"""docstring"""
@@ -15,5 +16,5 @@ class Class:
"""docstring"""
def meth(self, name: str = CONSTANT, sentinel: Any = SENTINEL,
- now: datetime = datetime.now()) -> None:
+ now: datetime = datetime.now(), color: int = 0xFFFFFF) -> None:
"""docstring"""
diff --git a/tests/test_ext_autodoc_preserve_defaults.py b/tests/test_ext_autodoc_preserve_defaults.py
index c0b5a9f29..955c60aa4 100644
--- a/tests/test_ext_autodoc_preserve_defaults.py
+++ b/tests/test_ext_autodoc_preserve_defaults.py
@@ -8,6 +8,8 @@
:license: BSD, see LICENSE for details.
"""
+import sys
+
import pytest
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',
confoverrides={'autodoc_preserve_defaults': True})
def test_preserve_defaults(app):
+ if sys.version_info < (3, 8):
+ color = "16777215"
+ else:
+ color = "0xFFFFFF"
+
options = {"members": None}
actual = do_autodoc(app, 'module', 'target.preserve_defaults', options)
assert list(actual) == [
@@ -30,14 +37,14 @@ def test_preserve_defaults(app):
'',
'',
' .. 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',
'',
' docstring',
'',
'',
'.. 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',
'',
' docstring',