mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
py domain: Support lambda functions in function signature
This commit is contained in:
1
CHANGES
1
CHANGES
@@ -44,6 +44,7 @@ Features added
|
||||
* #6558: glossary: emit a warning for duplicated glossary entry
|
||||
* #6558: std domain: emit a warning for duplicated generic objects
|
||||
* #6830: py domain: Add new event: :event:`object-description-transform`
|
||||
* py domain: Support lambda functions in function signature
|
||||
* Support priority of event handlers. For more detail, see
|
||||
:py:meth:`.Sphinx.connect()`
|
||||
* #3077: Implement the scoping for :rst:dir:`productionlist` as indicated
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"""
|
||||
|
||||
import sys
|
||||
from typing import List
|
||||
|
||||
if sys.version_info > (3, 8):
|
||||
import ast
|
||||
@@ -40,6 +41,13 @@ def unparse(node: ast.AST) -> str:
|
||||
return None
|
||||
elif isinstance(node, str):
|
||||
return node
|
||||
elif isinstance(node, ast.arg):
|
||||
if node.annotation:
|
||||
return "%s: %s" % (node.arg, unparse(node.annotation))
|
||||
else:
|
||||
return node.arg
|
||||
elif isinstance(node, ast.arguments):
|
||||
return unparse_arguments(node)
|
||||
elif isinstance(node, ast.Attribute):
|
||||
return "%s.%s" % (unparse(node.value), node.attr)
|
||||
elif isinstance(node, ast.Bytes):
|
||||
@@ -58,7 +66,7 @@ def unparse(node: ast.AST) -> str:
|
||||
elif isinstance(node, ast.Index):
|
||||
return unparse(node.value)
|
||||
elif isinstance(node, ast.Lambda):
|
||||
return "<function <lambda>>" # TODO
|
||||
return "lambda %s: ..." % unparse(node.args)
|
||||
elif isinstance(node, ast.List):
|
||||
return "[" + ", ".join(unparse(e) for e in node.elts) + "]"
|
||||
elif isinstance(node, ast.Name):
|
||||
@@ -80,3 +88,61 @@ def unparse(node: ast.AST) -> str:
|
||||
return repr(node.value)
|
||||
else:
|
||||
raise NotImplementedError('Unable to parse %s object' % type(node).__name__)
|
||||
|
||||
|
||||
def unparse_arguments(node: ast.arguments) -> str:
|
||||
"""Unparse an arguments to string."""
|
||||
defaults = list(node.defaults)
|
||||
positionals = len(node.args)
|
||||
posonlyargs = 0
|
||||
if hasattr(node, "posonlyargs"): # for py38+
|
||||
posonlyargs += len(node.posonlyargs) # type:ignore
|
||||
positionals += posonlyargs
|
||||
for _ in range(len(defaults), positionals):
|
||||
defaults.insert(0, None)
|
||||
|
||||
kw_defaults = list(node.kw_defaults)
|
||||
for _ in range(len(kw_defaults), len(node.kwonlyargs)):
|
||||
kw_defaults.insert(0, None)
|
||||
|
||||
args = [] # type: List[str]
|
||||
if hasattr(node, "posonlyargs"): # for py38+
|
||||
for i, arg in enumerate(node.posonlyargs): # type: ignore
|
||||
name = unparse(arg)
|
||||
if defaults[i]:
|
||||
if arg.annotation:
|
||||
name += " = %s" % unparse(defaults[i])
|
||||
else:
|
||||
name += "=%s" % unparse(defaults[i])
|
||||
args.append(name)
|
||||
|
||||
if node.posonlyargs: # type: ignore
|
||||
args.append('/')
|
||||
|
||||
for i, arg in enumerate(node.args):
|
||||
name = unparse(arg)
|
||||
if defaults[i + posonlyargs]:
|
||||
if arg.annotation:
|
||||
name += " = %s" % unparse(defaults[i + posonlyargs])
|
||||
else:
|
||||
name += "=%s" % unparse(defaults[i + posonlyargs])
|
||||
args.append(name)
|
||||
|
||||
if node.vararg:
|
||||
args.append("*" + unparse(node.vararg))
|
||||
|
||||
if node.kwonlyargs and not node.vararg:
|
||||
args.append('*')
|
||||
for i, arg in enumerate(node.kwonlyargs):
|
||||
name = unparse(arg)
|
||||
if kw_defaults[i]:
|
||||
if arg.annotation:
|
||||
name += " = %s" % unparse(kw_defaults[i])
|
||||
else:
|
||||
name += "=%s" % unparse(kw_defaults[i])
|
||||
args.append(name)
|
||||
|
||||
if node.kwarg:
|
||||
args.append("**" + unparse(node.kwarg))
|
||||
|
||||
return ", ".join(args)
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
from sphinx.pycode import ast
|
||||
@@ -23,7 +25,7 @@ from sphinx.pycode import ast
|
||||
("...", "..."), # Ellipsis
|
||||
("Tuple[int, int]", "Tuple[int, int]"), # Index, Subscript
|
||||
("lambda x, y: x + y",
|
||||
"<function <lambda>>"), # Lambda
|
||||
"lambda x, y: ..."), # Lambda
|
||||
("[1, 2, 3]", "[1, 2, 3]"), # List
|
||||
("sys", "sys"), # Name, NameConstant
|
||||
("1234", "1234"), # Num
|
||||
@@ -38,3 +40,11 @@ def test_unparse(source, expected):
|
||||
|
||||
def test_unparse_None():
|
||||
assert ast.unparse(None) is 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: ..."
|
||||
module = ast.parse(source)
|
||||
assert ast.unparse(module.body[0].value) == expected
|
||||
|
||||
Reference in New Issue
Block a user