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
|
* #8277: sphinx-build: missing and redundant spacing (and etc) for console
|
||||||
output on building
|
output on building
|
||||||
* #7973: imgconverter: Check availability of imagemagick many times
|
* #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,
|
* #8093: The highlight warning has wrong location in some builders (LaTeX,
|
||||||
singlehtml and so on)
|
singlehtml and so on)
|
||||||
* #8239: Failed to refer a token in productionlist if it is indented
|
* #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)
|
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."""
|
"""Unparse an AST to string."""
|
||||||
if node is None:
|
if node is None:
|
||||||
return None
|
return None
|
||||||
elif isinstance(node, str):
|
elif isinstance(node, str):
|
||||||
return node
|
return node
|
||||||
return _UnparseVisitor().visit(node)
|
return _UnparseVisitor(code).visit(node)
|
||||||
|
|
||||||
|
|
||||||
# a greatly cut-down version of `ast._Unparser`
|
# a greatly cut-down version of `ast._Unparser`
|
||||||
class _UnparseVisitor(ast.NodeVisitor):
|
class _UnparseVisitor(ast.NodeVisitor):
|
||||||
|
def __init__(self, code: str = '') -> None:
|
||||||
|
self.code = code
|
||||||
|
|
||||||
def _visit_op(self, node: ast.AST) -> str:
|
def _visit_op(self, node: ast.AST) -> str:
|
||||||
return OPERATORS[node.__class__]
|
return OPERATORS[node.__class__]
|
||||||
@ -195,6 +197,11 @@ class _UnparseVisitor(ast.NodeVisitor):
|
|||||||
def visit_Constant(self, node: ast.Constant) -> str:
|
def visit_Constant(self, node: ast.Constant) -> str:
|
||||||
if node.value is Ellipsis:
|
if node.value is Ellipsis:
|
||||||
return "..."
|
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:
|
else:
|
||||||
return repr(node.value)
|
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:
|
def signature_from_str(signature: str) -> inspect.Signature:
|
||||||
"""Create a Signature object from string."""
|
"""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
|
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*."""
|
"""Create a Signature object from AST *node*."""
|
||||||
args = node.args
|
args = node.args
|
||||||
defaults = list(args.defaults)
|
defaults = list(args.defaults)
|
||||||
@ -626,9 +627,9 @@ def signature_from_ast(node: ast.FunctionDef) -> inspect.Signature:
|
|||||||
if defaults[i] is Parameter.empty:
|
if defaults[i] is Parameter.empty:
|
||||||
default = Parameter.empty
|
default = Parameter.empty
|
||||||
else:
|
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,
|
params.append(Parameter(arg.arg, Parameter.POSITIONAL_ONLY,
|
||||||
default=default, annotation=annotation))
|
default=default, annotation=annotation))
|
||||||
|
|
||||||
@ -636,29 +637,29 @@ def signature_from_ast(node: ast.FunctionDef) -> inspect.Signature:
|
|||||||
if defaults[i + posonlyargs] is Parameter.empty:
|
if defaults[i + posonlyargs] is Parameter.empty:
|
||||||
default = Parameter.empty
|
default = Parameter.empty
|
||||||
else:
|
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,
|
params.append(Parameter(arg.arg, Parameter.POSITIONAL_OR_KEYWORD,
|
||||||
default=default, annotation=annotation))
|
default=default, annotation=annotation))
|
||||||
|
|
||||||
if args.vararg:
|
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,
|
params.append(Parameter(args.vararg.arg, Parameter.VAR_POSITIONAL,
|
||||||
annotation=annotation))
|
annotation=annotation))
|
||||||
|
|
||||||
for i, arg in enumerate(args.kwonlyargs):
|
for i, arg in enumerate(args.kwonlyargs):
|
||||||
default = ast_unparse(args.kw_defaults[i]) or Parameter.empty
|
default = ast_unparse(args.kw_defaults[i], code) or Parameter.empty
|
||||||
annotation = ast_unparse(arg.annotation) or Parameter.empty
|
annotation = ast_unparse(arg.annotation, code) or Parameter.empty
|
||||||
params.append(Parameter(arg.arg, Parameter.KEYWORD_ONLY, default=default,
|
params.append(Parameter(arg.arg, Parameter.KEYWORD_ONLY, default=default,
|
||||||
annotation=annotation))
|
annotation=annotation))
|
||||||
|
|
||||||
if args.kwarg:
|
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,
|
params.append(Parameter(args.kwarg.arg, Parameter.VAR_KEYWORD,
|
||||||
annotation=annotation))
|
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)
|
return inspect.Signature(params, return_annotation=return_annotation)
|
||||||
|
|
||||||
|
@ -386,6 +386,19 @@ def test_pyfunction_signature_full_py38(app):
|
|||||||
[desc_parameter, desc_sig_operator, "/"])])
|
[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):
|
def test_optional_pyfunction_signature(app):
|
||||||
text = ".. py:function:: compile(source [, filename [, symbol]]) -> ast object"
|
text = ".. py:function:: compile(source [, filename [, symbol]]) -> ast object"
|
||||||
doctree = restructuredtext.parse(app, text)
|
doctree = restructuredtext.parse(app, text)
|
||||||
|
@ -58,7 +58,7 @@ from sphinx.pycode import ast
|
|||||||
])
|
])
|
||||||
def test_unparse(source, expected):
|
def test_unparse(source, expected):
|
||||||
module = ast.parse(source)
|
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():
|
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.')
|
@pytest.mark.skipif(sys.version_info < (3, 8), reason='python 3.8+ is required.')
|
||||||
def test_unparse_py38():
|
@pytest.mark.parametrize('source,expected', [
|
||||||
source = "lambda x=0, /, y=1, *args, z, **kwargs: x + y + z"
|
("lambda x=0, /, y=1, *args, z, **kwargs: x + y + z",
|
||||||
expected = "lambda x=0, /, y=1, *args, z, **kwargs: ..."
|
"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)
|
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