Skip to content

Commit d38ef90

Browse files
Merge branch 'main' into solid-base
2 parents 4c3ad58 + 7ee9e05 commit d38ef90

File tree

3 files changed

+9
-18
lines changed

3 files changed

+9
-18
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
[`annotationlib.type_repr`](https://docs.python.org/3.14/library/annotationlib.html#annotationlib.type_repr),
77
introduced in Python 3.14 (CPython PR [#124551](https://github.com/python/cpython/pull/124551),
88
originally by Jelle Zijlstra). Patch by Semyon Moroz.
9+
- Fix behavior of type params in `typing_extensions.evaluate_forward_ref`. Backport of
10+
CPython PR [#137227](https://github.com/python/cpython/pull/137227) by Jelle Zijlstra.
911

1012
# Release 4.14.1 (July 4, 2025)
1113

src/test_typing_extensions.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9207,10 +9207,9 @@ class Gen[Tx]:
92079207
not_Tx = TypeVar("Tx") # different TypeVar with same name
92089208
self.assertIs(evaluate_forward_ref(typing.ForwardRef("Tx"), type_params=(not_Tx,), owner=Gen), not_Tx)
92099209

9210-
# globals can take higher precedence
9211-
if _FORWARD_REF_HAS_CLASS:
9212-
self.assertIs(evaluate_forward_ref(typing.ForwardRef("Tx", is_class=True), owner=Gen, globals={"Tx": str}), str)
9213-
self.assertIs(evaluate_forward_ref(typing.ForwardRef("Tx", is_class=True), owner=Gen, type_params=(not_Tx,), globals={"Tx": str}), str)
9210+
# globals do not take higher precedence
9211+
self.assertIs(evaluate_forward_ref(typing.ForwardRef("Tx", is_class=True), owner=Gen, globals={"Tx": str}), Tx)
9212+
self.assertIs(evaluate_forward_ref(typing.ForwardRef("Tx", is_class=True), owner=Gen, type_params=(not_Tx,), globals={"Tx": str}), not_Tx)
92149213

92159214
with self.assertRaises(NameError):
92169215
evaluate_forward_ref(typing.ForwardRef("alias"), type_params=Gen.__type_params__)

src/typing_extensions.py

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4093,23 +4093,13 @@ def _eval_with_owner(
40934093
# as a way of emulating annotation scopes when calling `eval()`
40944094
type_params = getattr(owner, "__type_params__", None)
40954095

4096-
# type parameters require some special handling,
4097-
# as they exist in their own scope
4098-
# but `eval()` does not have a dedicated parameter for that scope.
4099-
# For classes, names in type parameter scopes should override
4100-
# names in the global scope (which here are called `localns`!),
4101-
# but should in turn be overridden by names in the class scope
4102-
# (which here are called `globalns`!)
4096+
# Type parameters exist in their own scope, which is logically
4097+
# between the locals and the globals. We simulate this by adding
4098+
# them to the globals.
41034099
if type_params is not None:
41044100
globals = dict(globals)
4105-
locals = dict(locals)
41064101
for param in type_params:
4107-
param_name = param.__name__
4108-
if (
4109-
_FORWARD_REF_HAS_CLASS and not forward_ref.__forward_is_class__
4110-
) or param_name not in globals:
4111-
globals[param_name] = param
4112-
locals.pop(param_name, None)
4102+
globals[param.__name__] = param
41134103

41144104
arg = forward_ref.__forward_arg__
41154105
if arg.isidentifier() and not keyword.iskeyword(arg):

0 commit comments

Comments
 (0)