Skip to content

Commit

Permalink
Fix #9781: autodoc_preserve_defaults does not support hexadecimal
Browse files Browse the repository at this point in the history
  • Loading branch information
tk0miya committed Oct 30, 2021
1 parent 2b5c55e commit b8844eb
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 9 deletions.
2 changes: 2 additions & 0 deletions CHANGES
Expand Up @@ -66,6 +66,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
Expand Down
38 changes: 33 additions & 5 deletions sphinx/ext/autodoc/preserve_defaults.py
Expand Up @@ -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 __
Expand Down Expand Up @@ -49,11 +50,32 @@ 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:
Expand All @@ -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):
Expand Down
5 changes: 3 additions & 2 deletions tests/roots/test-ext-autodoc/target/preserve_defaults.py
Expand Up @@ -7,13 +7,14 @@

def foo(name: str = CONSTANT,
sentinel: Any = SENTINEL,
now: datetime = datetime.now()) -> None:
now: datetime = datetime.now(),
color: int = 0xFFFFFF) -> None:
"""docstring"""


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"""
11 changes: 9 additions & 2 deletions tests/test_ext_autodoc_preserve_defaults.py
Expand Up @@ -8,6 +8,8 @@
:license: BSD, see LICENSE for details.
"""

import sys

import pytest

from .test_ext_autodoc import do_autodoc
Expand All @@ -16,6 +18,11 @@
@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) == [
Expand All @@ -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',
Expand Down

0 comments on commit b8844eb

Please sign in to comment.