https://github.com/python/cpython/commit/453714a2dc0d16e6e6b8cff70801dfc1284bf74d
commit: 453714a2dc0d16e6e6b8cff70801dfc1284bf74d
branch: 3.15
author: Timofei <[email protected]>
committer: JelleZijlstra <[email protected]>
date: 2026-06-21T15:08:37-07:00
summary:
[3.15] gh-151665: Fix inspect.signature() on type alias and type parameter
evaluators (#151787)
files:
A Misc/NEWS.d/next/Library/2026-06-20-14-47-55.gh-issue-151665.82fmzx.rst
M Lib/inspect.py
M Lib/test/test_type_params.py
diff --git a/Lib/inspect.py b/Lib/inspect.py
index dc5a6e3be883bb..0dbd596db16023 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -2720,6 +2720,10 @@ def __init__(self, name, kind, *, default=_empty,
annotation=_empty):
raise ValueError(msg)
self._kind = _POSITIONAL_ONLY
name = 'implicit{}'.format(name[1:])
+ elif name == '.format':
+ # gh-151665: Hidden parameter of compiler-generated annotation and
type
+ # alias/typevar evaluators. Show it as "format".
+ name = 'format'
# It's possible for C functions to have a positional-only parameter
# where the name is a keyword, so for compatibility we'll allow it.
diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py
index 84c1b954136736..27660379ec43a3 100644
--- a/Lib/test/test_type_params.py
+++ b/Lib/test/test_type_params.py
@@ -1,4 +1,5 @@
import annotationlib
+import inspect
import textwrap
import types
import unittest
@@ -1446,6 +1447,30 @@ def f[T: int = int, **P = int, *Ts = int](): pass
self.assertIs(annotationlib.call_evaluate_function(case,
annotationlib.Format.FORWARDREF), int)
self.assertEqual(annotationlib.call_evaluate_function(case,
annotationlib.Format.STRING), 'int')
+ def test_signature(self):
+ # gh-151665: the ".format" parameter of compiler-generated evaluators
+ # used to break inspect.signature(). It should show up as "format".
+ type Alias = int
+ def f[T: int = int, **P = int, *Ts = int](): pass
+ T, P, Ts = f.__type_params__
+ def g[T: (int, str)](): pass
+ T3, = g.__type_params__
+ cases = [
+ Alias.evaluate_value,
+ T.evaluate_bound,
+ T.evaluate_default,
+ P.evaluate_default,
+ Ts.evaluate_default,
+ T3.evaluate_constraints,
+ ]
+ for case in cases:
+ with self.subTest(case=case):
+ sig = inspect.signature(case)
+ self.assertEqual(str(sig), '(format=1, /)')
+ param, = sig.parameters.values()
+ self.assertEqual(param.name, 'format')
+ self.assertIs(param.kind, inspect.Parameter.POSITIONAL_ONLY)
+
def test_constraints(self):
def f[T: (int, str)](): pass
T, = f.__type_params__
diff --git
a/Misc/NEWS.d/next/Library/2026-06-20-14-47-55.gh-issue-151665.82fmzx.rst
b/Misc/NEWS.d/next/Library/2026-06-20-14-47-55.gh-issue-151665.82fmzx.rst
new file mode 100644
index 00000000000000..d08a1220cbe5ef
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-06-20-14-47-55.gh-issue-151665.82fmzx.rst
@@ -0,0 +1,2 @@
+:func:`inspect.signature` now works on the lazy evaluators of type aliases
+and type parameters instead of raising :exc:`ValueError`.
_______________________________________________
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]