https://github.com/python/cpython/commit/f4f598a28a52e030124fbf24b89b501d1ffc1647
commit: f4f598a28a52e030124fbf24b89b501d1ffc1647
branch: 3.13
author: Brian Schubert <[email protected]>
committer: JelleZijlstra <[email protected]>
date: 2026-03-26T21:39:27Z
summary:

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

(cherry picked from commit c6be6e453730228053783f3444cb62e1425a3feb)

Co-authored-by: Christoph Walcher <[email protected]>

files:
A Misc/NEWS.d/next/Library/2025-09-15-21-03-11.gh-issue-138891.oZFdtR.rst
M Lib/inspect.py
M Lib/test/test_inspect/test_inspect.py
M Lib/typing.py

diff --git a/Lib/inspect.py b/Lib/inspect.py
index b1f3b9fc8dfb0a..d74444e27bed5c 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -160,6 +160,7 @@
 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
 
diff --git a/Lib/test/test_inspect/test_inspect.py 
b/Lib/test/test_inspect/test_inspect.py
index 3ebb305606211d..a4c5ac2e909c76 100644
--- a/Lib/test/test_inspect/test_inspect.py
+++ b/Lib/test/test_inspect/test_inspect.py
@@ -1859,6 +1859,10 @@ def 
test_get_annotations_with_stringized_annotations(self):
         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):
diff --git a/Lib/typing.py b/Lib/typing.py
index 67b1ef329d5932..cbc6d90e13a830 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -1024,15 +1024,8 @@ def __init__(self, arg, is_argument=True, module=None, 
*, is_class=False):
         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 @@ def __repr__(self):
         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))
diff --git 
a/Misc/NEWS.d/next/Library/2025-09-15-21-03-11.gh-issue-138891.oZFdtR.rst 
b/Misc/NEWS.d/next/Library/2025-09-15-21-03-11.gh-issue-138891.oZFdtR.rst
new file mode 100644
index 00000000000000..f7ecb05d20c241
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-09-15-21-03-11.gh-issue-138891.oZFdtR.rst
@@ -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``

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to