[3.13] gh-138891: fix star-unpack in get_annotations (GH-138951) (#146491)

(cherry picked from commit c6be6e4537)

Co-authored-by: Christoph Walcher <christoph-wa@gmx.de>
This commit is contained in:
Brian Schubert
2026-03-26 17:39:27 -04:00
committed by GitHub
parent 2bb1ac2162
commit f4f598a28a
4 changed files with 21 additions and 10 deletions
+4 -2
View File
@@ -160,6 +160,7 @@ import builtins
from keyword import iskeyword
from operator import attrgetter
from collections import namedtuple, OrderedDict
from typing import _rewrite_star_unpack
from weakref import ref as make_weakref
# Create constants for the compiler flags in Include/code.h
@@ -288,8 +289,9 @@ def get_annotations(obj, *, globals=None, locals=None, eval_str=False):
if type_params := getattr(obj, "__type_params__", ()):
locals = {param.__name__: param for param in type_params} | locals
return_value = {key:
value if not isinstance(value, str) else eval(value, globals, locals)
return_value = {
key: value if not isinstance(value, str)
else eval(_rewrite_star_unpack(value), globals, locals)
for key, value in ann.items() }
return return_value
+4
View File
@@ -1859,6 +1859,10 @@ class TestClassesAndFunctions(unittest.TestCase):
self.assertEqual(inspect.get_annotations(isa2, eval_str=True), {})
self.assertEqual(inspect.get_annotations(isa2, eval_str=False), {})
def f(*args: *tuple[int, ...]): ...
self.assertEqual(inspect.get_annotations(f, eval_str=True),
{'args': (*tuple[int, ...],)[0]})
def times_three(fn):
@functools.wraps(fn)
def wrapper(a, b):
+11 -8
View File
@@ -1024,15 +1024,8 @@ class ForwardRef(_Final, _root=True):
if not isinstance(arg, str):
raise TypeError(f"Forward reference must be a string -- got {arg!r}")
# If we do `def f(*args: *Ts)`, then we'll have `arg = '*Ts'`.
# Unfortunately, this isn't a valid expression on its own, so we
# do the unpacking manually.
if arg.startswith('*'):
arg_to_compile = f'({arg},)[0]' # E.g. (*Ts,)[0] or (*tuple[int, int],)[0]
else:
arg_to_compile = arg
try:
code = compile(arg_to_compile, '<string>', 'eval')
code = compile(_rewrite_star_unpack(arg), '<string>', 'eval')
except SyntaxError:
raise SyntaxError(f"Forward reference must be an expression -- got {arg!r}")
@@ -1119,6 +1112,16 @@ class ForwardRef(_Final, _root=True):
return f'ForwardRef({self.__forward_arg__!r}{module_repr})'
def _rewrite_star_unpack(arg):
"""If the given argument annotation expression is a star unpack e.g. `'*Ts'`
rewrite it to a valid expression.
"""
if arg.startswith("*"):
return f"({arg},)[0]" # E.g. (*Ts,)[0] or (*tuple[int, int],)[0]
else:
return arg
def _is_unpacked_typevartuple(x: Any) -> bool:
return ((not isinstance(x, type)) and
getattr(x, '__typing_is_unpacked_typevartuple__', False))
@@ -0,0 +1,2 @@
Fix ``SyntaxError`` when ``inspect.get_annotations(f, eval_str=True)`` is
called on a function annotated with a :pep:`646` ``star_expression``