Skip to content

Commit

Permalink
pythongh-81677: basic support for annotations in signature strings
Browse files Browse the repository at this point in the history
  • Loading branch information
skirpichev committed Feb 13, 2023
1 parent 6ef6915 commit af8609c
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 4 deletions.
29 changes: 25 additions & 4 deletions Lib/inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -2208,10 +2208,22 @@ def _signature_fromstr(cls, obj, s, skip_bound_arg=True):

def parse_name(node):
assert isinstance(node, ast.arg)
if node.annotation is not None:
raise ValueError("Annotations are not currently supported")
return node.arg

def parse_annotation(node):
assert isinstance(node, (ast.arg, ast.FunctionDef))
if isinstance(node, ast.arg):
annotation = node.annotation
else:
annotation = node.returns
if annotation:
expr = ast.unparse(annotation)
try:
return eval(expr, sys_module_dict)
except NameError:
raise ValueError
return empty

def wrap_value(s):
try:
value = eval(s, module_dict)
Expand Down Expand Up @@ -2266,7 +2278,11 @@ def p(name_node, default_node, default=empty):
default = ast.literal_eval(default_node)
except ValueError:
raise ValueError("{!r} builtin has invalid signature".format(obj)) from None
parameters.append(Parameter(name, kind, default=default, annotation=empty))
try:
annotation = parse_annotation(name_node)
except ValueError:
raise ValueError("{!r} builtin has invalid signature".format(obj)) from None
parameters.append(Parameter(name, kind, default=default, annotation=annotation))

# non-keyword-only parameters
args = reversed(f.args.args)
Expand Down Expand Up @@ -2313,7 +2329,12 @@ def p(name_node, default_node, default=empty):
p = parameters[0].replace(kind=Parameter.POSITIONAL_ONLY)
parameters[0] = p

return cls(parameters, return_annotation=cls.empty)
try:
return_annotation = parse_annotation(f)
except ValueError:
raise ValueError("{!r} builtin has invalid signature".format(obj)) from None

return cls(parameters, return_annotation=return_annotation)


def _signature_from_builtin(cls, func, skip_bound_arg=True):
Expand Down
27 changes: 27 additions & 0 deletions Lib/test/test_inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -4384,6 +4384,33 @@ class MyBufferedReader(BufferedReader):
sig = inspect.signature(MyBufferedReader)
self.assertEqual(str(sig), '(raw, buffer_size=8192)')

def test_annotations_in_text_signature(self):
def func(*args, **kwargs):
pass

func.__text_signature__ = '($self, a: int) -> list'
sig = inspect.signature(func)
self.assertIsNotNone(sig)
self.assertEqual(str(sig), '(self, /, a: int) -> list')

func.__text_signature__ = '($self, a: int | float)'
sig = inspect.signature(func)
self.assertIsNotNone(sig)
self.assertEqual(str(sig), '(self, /, a: int | float)')

func.__text_signature__ = '($self, a: tuple[int, ...])'
sig = inspect.signature(func)
self.assertIsNotNone(sig)
self.assertEqual(str(sig), '(self, /, a: tuple[int, ...])')

func.__text_signature__ = '(self, x: spam)'
with self.assertRaises(ValueError):
inspect.signature(func)

func.__text_signature__ = '(self, x) -> spam'
with self.assertRaises(ValueError):
inspect.signature(func)


class NTimesUnwrappable:
def __init__(self, n):
Expand Down

0 comments on commit af8609c

Please sign in to comment.