mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge pull request #8278 from tk0miya/8255_hexadecimal_default_value
Fix #8255: py domain: number in defarg is changed to decimal
This commit is contained in:
commit
408ebe4105
2
CHANGES
2
CHANGES
@ -49,6 +49,8 @@ Bugs fixed
|
||||
* #8277: sphinx-build: missing and redundant spacing (and etc) for console
|
||||
output on building
|
||||
* #7973: imgconverter: Check availability of imagemagick many times
|
||||
* #8255: py domain: number in default argument value is changed from hexadecimal
|
||||
to decimal
|
||||
* #8093: The highlight warning has wrong location in some builders (LaTeX,
|
||||
singlehtml and so on)
|
||||
* #8239: Failed to refer a token in productionlist if it is indented
|
||||
|
@ -58,17 +58,19 @@ def parse(code: str, mode: str = 'exec') -> "ast.AST":
|
||||
return ast.parse(code, mode=mode)
|
||||
|
||||
|
||||
def unparse(node: Optional[ast.AST]) -> Optional[str]:
|
||||
def unparse(node: Optional[ast.AST], code: str = '') -> Optional[str]:
|
||||
"""Unparse an AST to string."""
|
||||
if node is None:
|
||||
return None
|
||||
elif isinstance(node, str):
|
||||
return node
|
||||
return _UnparseVisitor().visit(node)
|
||||
return _UnparseVisitor(code).visit(node)
|
||||
|
||||
|
||||
# a greatly cut-down version of `ast._Unparser`
|
||||
class _UnparseVisitor(ast.NodeVisitor):
|
||||
def __init__(self, code: str = '') -> None:
|
||||
self.code = code
|
||||
|
||||
def _visit_op(self, node: ast.AST) -> str:
|
||||
return OPERATORS[node.__class__]
|
||||
@ -195,6 +197,11 @@ class _UnparseVisitor(ast.NodeVisitor):
|
||||
def visit_Constant(self, node: ast.Constant) -> str:
|
||||
if node.value is Ellipsis:
|
||||
return "..."
|
||||
elif isinstance(node.value, (int, float, complex)):
|
||||
if self.code and sys.version_info > (3, 8):
|
||||
return ast.get_source_segment(self.code, node)
|
||||
else:
|
||||
return repr(node.value)
|
||||
else:
|
||||
return repr(node.value)
|
||||
|
||||
|
@ -600,13 +600,14 @@ def stringify_signature(sig: inspect.Signature, show_annotation: bool = True,
|
||||
|
||||
def signature_from_str(signature: str) -> inspect.Signature:
|
||||
"""Create a Signature object from string."""
|
||||
module = ast.parse('def func' + signature + ': pass')
|
||||
code = 'def func' + signature + ': pass'
|
||||
module = ast.parse(code)
|
||||
function = cast(ast.FunctionDef, module.body[0]) # type: ignore
|
||||
|
||||
return signature_from_ast(function)
|
||||
return signature_from_ast(function, code)
|
||||
|
||||
|
||||
def signature_from_ast(node: ast.FunctionDef) -> inspect.Signature:
|
||||
def signature_from_ast(node: ast.FunctionDef, code: str = '') -> inspect.Signature:
|
||||
"""Create a Signature object from AST *node*."""
|
||||
args = node.args
|
||||
defaults = list(args.defaults)
|
||||
@ -626,9 +627,9 @@ def signature_from_ast(node: ast.FunctionDef) -> inspect.Signature:
|
||||
if defaults[i] is Parameter.empty:
|
||||
default = Parameter.empty
|
||||
else:
|
||||
default = ast_unparse(defaults[i])
|
||||
default = ast_unparse(defaults[i], code)
|
||||
|
||||
annotation = ast_unparse(arg.annotation) or Parameter.empty
|
||||
annotation = ast_unparse(arg.annotation, code) or Parameter.empty
|
||||
params.append(Parameter(arg.arg, Parameter.POSITIONAL_ONLY,
|
||||
default=default, annotation=annotation))
|
||||
|
||||
@ -636,29 +637,29 @@ def signature_from_ast(node: ast.FunctionDef) -> inspect.Signature:
|
||||
if defaults[i + posonlyargs] is Parameter.empty:
|
||||
default = Parameter.empty
|
||||
else:
|
||||
default = ast_unparse(defaults[i + posonlyargs])
|
||||
default = ast_unparse(defaults[i + posonlyargs], code)
|
||||
|
||||
annotation = ast_unparse(arg.annotation) or Parameter.empty
|
||||
annotation = ast_unparse(arg.annotation, code) or Parameter.empty
|
||||
params.append(Parameter(arg.arg, Parameter.POSITIONAL_OR_KEYWORD,
|
||||
default=default, annotation=annotation))
|
||||
|
||||
if args.vararg:
|
||||
annotation = ast_unparse(args.vararg.annotation) or Parameter.empty
|
||||
annotation = ast_unparse(args.vararg.annotation, code) or Parameter.empty
|
||||
params.append(Parameter(args.vararg.arg, Parameter.VAR_POSITIONAL,
|
||||
annotation=annotation))
|
||||
|
||||
for i, arg in enumerate(args.kwonlyargs):
|
||||
default = ast_unparse(args.kw_defaults[i]) or Parameter.empty
|
||||
annotation = ast_unparse(arg.annotation) or Parameter.empty
|
||||
default = ast_unparse(args.kw_defaults[i], code) or Parameter.empty
|
||||
annotation = ast_unparse(arg.annotation, code) or Parameter.empty
|
||||
params.append(Parameter(arg.arg, Parameter.KEYWORD_ONLY, default=default,
|
||||
annotation=annotation))
|
||||
|
||||
if args.kwarg:
|
||||
annotation = ast_unparse(args.kwarg.annotation) or Parameter.empty
|
||||
annotation = ast_unparse(args.kwarg.annotation, code) or Parameter.empty
|
||||
params.append(Parameter(args.kwarg.arg, Parameter.VAR_KEYWORD,
|
||||
annotation=annotation))
|
||||
|
||||
return_annotation = ast_unparse(node.returns) or Parameter.empty
|
||||
return_annotation = ast_unparse(node.returns, code) or Parameter.empty
|
||||
|
||||
return inspect.Signature(params, return_annotation=return_annotation)
|
||||
|
||||
|
@ -386,6 +386,19 @@ def test_pyfunction_signature_full_py38(app):
|
||||
[desc_parameter, desc_sig_operator, "/"])])
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 8), reason='python 3.8+ is required.')
|
||||
def test_pyfunction_with_number_literals(app):
|
||||
text = ".. py:function:: hello(age=0x10, height=1_6_0)"
|
||||
doctree = restructuredtext.parse(app, text)
|
||||
assert_node(doctree[1][0][1],
|
||||
[desc_parameterlist, ([desc_parameter, ([desc_sig_name, "age"],
|
||||
[desc_sig_operator, "="],
|
||||
[nodes.inline, "0x10"])],
|
||||
[desc_parameter, ([desc_sig_name, "height"],
|
||||
[desc_sig_operator, "="],
|
||||
[nodes.inline, "1_6_0"])])])
|
||||
|
||||
|
||||
def test_optional_pyfunction_signature(app):
|
||||
text = ".. py:function:: compile(source [, filename [, symbol]]) -> ast object"
|
||||
doctree = restructuredtext.parse(app, text)
|
||||
|
@ -58,7 +58,7 @@ from sphinx.pycode import ast
|
||||
])
|
||||
def test_unparse(source, expected):
|
||||
module = ast.parse(source)
|
||||
assert ast.unparse(module.body[0].value) == expected
|
||||
assert ast.unparse(module.body[0].value, source) == expected
|
||||
|
||||
|
||||
def test_unparse_None():
|
||||
@ -66,8 +66,12 @@ def test_unparse_None():
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 8), reason='python 3.8+ is required.')
|
||||
def test_unparse_py38():
|
||||
source = "lambda x=0, /, y=1, *args, z, **kwargs: x + y + z"
|
||||
expected = "lambda x=0, /, y=1, *args, z, **kwargs: ..."
|
||||
@pytest.mark.parametrize('source,expected', [
|
||||
("lambda x=0, /, y=1, *args, z, **kwargs: x + y + z",
|
||||
"lambda x=0, /, y=1, *args, z, **kwargs: ..."), # posonlyargs
|
||||
("0x1234", "0x1234"), # Constant
|
||||
("1_000_000", "1_000_000"), # Constant
|
||||
])
|
||||
def test_unparse_py38(source, expected):
|
||||
module = ast.parse(source)
|
||||
assert ast.unparse(module.body[0].value) == expected
|
||||
assert ast.unparse(module.body[0].value, source) == expected
|
||||
|
Loading…
Reference in New Issue
Block a user