summaryrefslogtreecommitdiff
path: root/sphinx/pycode/ast.py
diff options
context:
space:
mode:
Diffstat (limited to 'sphinx/pycode/ast.py')
-rw-r--r--sphinx/pycode/ast.py68
1 files changed, 67 insertions, 1 deletions
diff --git a/sphinx/pycode/ast.py b/sphinx/pycode/ast.py
index 22207b715..52617e3bc 100644
--- a/sphinx/pycode/ast.py
+++ b/sphinx/pycode/ast.py
@@ -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)