Skip to content

Commit af8609c

Browse files
committed
gh-81677: basic support for annotations in signature strings
1 parent 6ef6915 commit af8609c

2 files changed

Lines changed: 52 additions & 4 deletions

File tree

Lib/inspect.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2208,10 +2208,22 @@ def _signature_fromstr(cls, obj, s, skip_bound_arg=True):
22082208

22092209
def parse_name(node):
22102210
assert isinstance(node, ast.arg)
2211-
if node.annotation is not None:
2212-
raise ValueError("Annotations are not currently supported")
22132211
return node.arg
22142212

2213+
def parse_annotation(node):
2214+
assert isinstance(node, (ast.arg, ast.FunctionDef))
2215+
if isinstance(node, ast.arg):
2216+
annotation = node.annotation
2217+
else:
2218+
annotation = node.returns
2219+
if annotation:
2220+
expr = ast.unparse(annotation)
2221+
try:
2222+
return eval(expr, sys_module_dict)
2223+
except NameError:
2224+
raise ValueError
2225+
return empty
2226+
22152227
def wrap_value(s):
22162228
try:
22172229
value = eval(s, module_dict)
@@ -2266,7 +2278,11 @@ def p(name_node, default_node, default=empty):
22662278
default = ast.literal_eval(default_node)
22672279
except ValueError:
22682280
raise ValueError("{!r} builtin has invalid signature".format(obj)) from None
2269-
parameters.append(Parameter(name, kind, default=default, annotation=empty))
2281+
try:
2282+
annotation = parse_annotation(name_node)
2283+
except ValueError:
2284+
raise ValueError("{!r} builtin has invalid signature".format(obj)) from None
2285+
parameters.append(Parameter(name, kind, default=default, annotation=annotation))
22702286

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

2316-
return cls(parameters, return_annotation=cls.empty)
2332+
try:
2333+
return_annotation = parse_annotation(f)
2334+
except ValueError:
2335+
raise ValueError("{!r} builtin has invalid signature".format(obj)) from None
2336+
2337+
return cls(parameters, return_annotation=return_annotation)
23172338

23182339

23192340
def _signature_from_builtin(cls, func, skip_bound_arg=True):

Lib/test/test_inspect.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4384,6 +4384,33 @@ class MyBufferedReader(BufferedReader):
43844384
sig = inspect.signature(MyBufferedReader)
43854385
self.assertEqual(str(sig), '(raw, buffer_size=8192)')
43864386

4387+
def test_annotations_in_text_signature(self):
4388+
def func(*args, **kwargs):
4389+
pass
4390+
4391+
func.__text_signature__ = '($self, a: int) -> list'
4392+
sig = inspect.signature(func)
4393+
self.assertIsNotNone(sig)
4394+
self.assertEqual(str(sig), '(self, /, a: int) -> list')
4395+
4396+
func.__text_signature__ = '($self, a: int | float)'
4397+
sig = inspect.signature(func)
4398+
self.assertIsNotNone(sig)
4399+
self.assertEqual(str(sig), '(self, /, a: int | float)')
4400+
4401+
func.__text_signature__ = '($self, a: tuple[int, ...])'
4402+
sig = inspect.signature(func)
4403+
self.assertIsNotNone(sig)
4404+
self.assertEqual(str(sig), '(self, /, a: tuple[int, ...])')
4405+
4406+
func.__text_signature__ = '(self, x: spam)'
4407+
with self.assertRaises(ValueError):
4408+
inspect.signature(func)
4409+
4410+
func.__text_signature__ = '(self, x) -> spam'
4411+
with self.assertRaises(ValueError):
4412+
inspect.signature(func)
4413+
43874414

43884415
class NTimesUnwrappable:
43894416
def __init__(self, n):

0 commit comments

Comments
 (0)