commit:     96ce6d9ee301206926396d1f99fcb9b2bb7b0caa
Author:     Sam James <sam <AT> gentoo <DOT> org>
AuthorDate: Thu May  8 21:12:51 2025 +0000
Commit:     Sam James <sam <AT> gentoo <DOT> org>
CommitDate: Thu May  8 21:13:13 2025 +0000
URL:        https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=96ce6d9e

dev-python/typing-extensions: add missing patch

Couldn't test w/ py3.14 as don't have it installed yet, but passes
tests otherwise.

Closes: https://bugs.gentoo.org/955647
Signed-off-by: Sam James <sam <AT> gentoo.org>

 .../files/typing-extensions-4.13.2-py314.patch     | 596 +++++++++++++++++++++
 1 file changed, 596 insertions(+)

diff --git 
a/dev-python/typing-extensions/files/typing-extensions-4.13.2-py314.patch 
b/dev-python/typing-extensions/files/typing-extensions-4.13.2-py314.patch
new file mode 100644
index 000000000000..e19a86f61e29
--- /dev/null
+++ b/dev-python/typing-extensions/files/typing-extensions-4.13.2-py314.patch
@@ -0,0 +1,596 @@
+https://github.com/python/typing_extensions/pull/566
+https://github.com/python/typing_extensions/pull/592
+(CI bits dropped, test_fwdref_value_is_cached hunk added at the end as
+didn't apply cleanly.)
+
+From 32dde8e38975df88336107b112300483325010ef Mon Sep 17 00:00:00 2001
+From: Jelle Zijlstra <[email protected]>
+Date: Tue, 1 Apr 2025 08:26:52 -0700
+Subject: [PATCH 1/3] Fix test failures on Python 3.14
+
+--- a/src/test_typing_extensions.py
++++ b/src/test_typing_extensions.py
+@@ -882,10 +882,12 @@ async def coro(self):
+ 
+ class DeprecatedCoroTests(BaseTestCase):
+     def test_asyncio_iscoroutinefunction(self):
+-        self.assertFalse(asyncio.coroutines.iscoroutinefunction(func))
+-        self.assertFalse(asyncio.coroutines.iscoroutinefunction(Cls.func))
+-        self.assertTrue(asyncio.coroutines.iscoroutinefunction(coro))
+-        self.assertTrue(asyncio.coroutines.iscoroutinefunction(Cls.coro))
++        with warnings.catch_warnings():
++            warnings.simplefilter("ignore", DeprecationWarning)
++            self.assertFalse(asyncio.coroutines.iscoroutinefunction(func))
++            self.assertFalse(asyncio.coroutines.iscoroutinefunction(Cls.func))
++            self.assertTrue(asyncio.coroutines.iscoroutinefunction(coro))
++            self.assertTrue(asyncio.coroutines.iscoroutinefunction(Cls.coro))
+ 
+     @skipUnless(TYPING_3_12_ONLY or TYPING_3_13_0_RC, 
"inspect.iscoroutinefunction works differently on Python < 3.12")
+     def test_inspect_iscoroutinefunction(self):
+@@ -7209,7 +7211,7 @@ def test_cannot_instantiate_vars(self):
+ 
+     def test_bound_errors(self):
+         with self.assertRaises(TypeError):
+-            TypeVar('X', bound=Union)
++            TypeVar('X', bound=Optional)
+         with self.assertRaises(TypeError):
+             TypeVar('X', str, float, bound=Employee)
+         with self.assertRaisesRegex(TypeError,
+@@ -8190,19 +8192,25 @@ def f2(a: "undefined"):  # noqa: F821
+             get_annotations(f2, format=Format.FORWARDREF),
+             {"a": "undefined"},
+         )
+-        self.assertEqual(get_annotations(f2, format=2), {"a": "undefined"})
++        self.assertEqual(
++            get_annotations(f2, format=Format.FORWARDREF.value),
++            {"a": "undefined"},
++        )
+ 
+         self.assertEqual(
+             get_annotations(f1, format=Format.STRING),
+             {"a": "int"},
+         )
+-        self.assertEqual(get_annotations(f1, format=3), {"a": "int"})
++        self.assertEqual(
++            get_annotations(f1, format=Format.STRING.value),
++            {"a": "int"},
++        )
+ 
+         with self.assertRaises(ValueError):
+             get_annotations(f1, format=0)
+ 
+         with self.assertRaises(ValueError):
+-            get_annotations(f1, format=4)
++            get_annotations(f1, format=42)
+ 
+     def test_custom_object_with_annotations(self):
+         class C:
+@@ -8240,6 +8248,8 @@ def foo(a: int, b: str):
+ 
+         foo.__annotations__ = {"a": "foo", "b": "str"}
+         for format in Format:
++            if format is Format.VALUE_WITH_FAKE_GLOBALS:
++                continue
+             with self.subTest(format=format):
+                 self.assertEqual(
+                     get_annotations(foo, format=format),
+--- a/src/typing_extensions.py
++++ b/src/typing_extensions.py
+@@ -4139,8 +4139,9 @@ def __eq__(self, other: object) -> bool:
+ 
+ class Format(enum.IntEnum):
+     VALUE = 1
+-    FORWARDREF = 2
+-    STRING = 3
++    VALUE_WITH_FAKE_GLOBALS = 2
++    FORWARDREF = 3
++    STRING = 4
+ 
+ 
+ if _PEP_649_OR_749_IMPLEMENTED:
+@@ -4184,6 +4185,8 @@ def get_annotations(obj, *, globals=None, locals=None, 
eval_str=False,
+ 
+         """
+         format = Format(format)
++        if format is Format.VALUE_WITH_FAKE_GLOBALS:
++            raise ValueError("The VALUE_WITH_FAKE_GLOBALS format is for 
internal use only")
+ 
+         if eval_str and format is not Format.VALUE:
+             raise ValueError("eval_str=True is only supported with 
format=Format.VALUE")
+
+From c98e556ee2e4c7b9964297d827ef57da4d916b3d Mon Sep 17 00:00:00 2001
+From: Jelle Zijlstra <[email protected]>
+Date: Tue, 1 Apr 2025 08:31:01 -0700
+Subject: [PATCH 2/3] test & lint
+
+--- a/src/test_typing_extensions.py
++++ b/src/test_typing_extensions.py
+@@ -8248,13 +8248,18 @@ def foo(a: int, b: str):
+ 
+         foo.__annotations__ = {"a": "foo", "b": "str"}
+         for format in Format:
+-            if format is Format.VALUE_WITH_FAKE_GLOBALS:
+-                continue
+             with self.subTest(format=format):
+-                self.assertEqual(
+-                    get_annotations(foo, format=format),
+-                    {"a": "foo", "b": "str"},
+-                )
++                if format is Format.VALUE_WITH_FAKE_GLOBALS:
++                    with self.assertRaisesRegex(
++                        ValueError,
++                        "The VALUE_WITH_FAKE_GLOBALS format is for internal 
use only"
++                    ):
++                        get_annotations(foo, format=format)
++                else:
++                    self.assertEqual(
++                        get_annotations(foo, format=format),
++                        {"a": "foo", "b": "str"},
++                    )
+ 
+         self.assertEqual(
+             get_annotations(foo, eval_str=True, locals=locals()),
+--- a/src/typing_extensions.py
++++ b/src/typing_extensions.py
+@@ -4186,7 +4186,9 @@ def get_annotations(obj, *, globals=None, locals=None, 
eval_str=False,
+         """
+         format = Format(format)
+         if format is Format.VALUE_WITH_FAKE_GLOBALS:
+-            raise ValueError("The VALUE_WITH_FAKE_GLOBALS format is for 
internal use only")
++            raise ValueError(
++                "The VALUE_WITH_FAKE_GLOBALS format is for internal use only"
++            )
+ 
+         if eval_str and format is not Format.VALUE:
+             raise ValueError("eval_str=True is only supported with 
format=Format.VALUE")
+
+From adfb57a83f358e26905531407edf99a7346e22fc Mon Sep 17 00:00:00 2001
+From: Jelle Zijlstra <[email protected]>
+Date: Thu, 10 Apr 2025 07:09:20 -0700
+Subject: [PATCH 3/3] Update src/test_typing_extensions.py
+
+--- a/src/test_typing_extensions.py
++++ b/src/test_typing_extensions.py
+@@ -8196,6 +8196,7 @@ def f2(a: "undefined"):  # noqa: F821
+             get_annotations(f2, format=Format.FORWARDREF),
+             {"a": "undefined"},
+         )
++        # Test that the raw int also works
+         self.assertEqual(
+             get_annotations(f2, format=Format.FORWARDREF.value),
+             {"a": "undefined"},
+From 610ad76f7c4b8ff67deb6d688c00ccc7530ef363 Mon Sep 17 00:00:00 2001
+From: Jelle Zijlstra <[email protected]>
+Date: Mon, 5 May 2025 07:52:14 -0700
+Subject: [PATCH 1/5] Fix 3.14
+
+--- a/src/test_typing_extensions.py
++++ b/src/test_typing_extensions.py
+@@ -5152,6 +5152,65 @@ def test_inline(self):
+         self.assertIs(type(inst), dict)
+         self.assertEqual(inst["a"], 1)
+ 
++    def test_annotations(self):
++        # _type_check is applied
++        with self.assertRaisesRegex(TypeError, "Plain typing.Final is not 
valid as type argument"):
++            class X(TypedDict):
++                a: Final
++
++        # _type_convert is applied
++        class Y(TypedDict):
++            a: None
++            b: "int"
++        if sys.version_info >= (3, 14):
++            import annotationlib
++            from test.support import EqualToForwardRef
++
++            fwdref = EqualToForwardRef('int', module=__name__)
++            self.assertEqual(Y.__annotations__, {'a': type(None), 'b': 
fwdref})
++            self.assertEqual(Y.__annotate__(annotationlib.Format.FORWARDREF), 
{'a': type(None), 'b': fwdref})
++        else:
++            self.assertEqual(Y.__annotations__, {'a': type(None), 'b': 
typing.ForwardRef('int', module=__name__)})
++
++    @skipUnless(TYPING_3_14_0, "Only supported on 3.14")
++    def test_delayed_type_check(self):
++        # _type_check is also applied later
++        class Z(TypedDict):
++            a: undefined
++
++        with self.assertRaises(NameError):
++            Z.__annotations__
++
++        undefined = Final
++        with self.assertRaisesRegex(TypeError, "Plain typing.Final is not 
valid as type argument"):
++            Z.__annotations__
++
++        undefined = None
++        self.assertEqual(Z.__annotations__, {'a': type(None)})
++
++    @skipUnless(TYPING_3_14_0, "Only supported on 3.14")
++    def test_deferred_evaluation(self):
++        class A(TypedDict):
++            x: NotRequired[undefined]
++            y: ReadOnly[undefined]
++            z: Required[undefined]
++
++        self.assertEqual(A.__required_keys__, frozenset({'y', 'z'}))
++        self.assertEqual(A.__optional_keys__, frozenset({'x'}))
++        self.assertEqual(A.__readonly_keys__, frozenset({'y'}))
++        self.assertEqual(A.__mutable_keys__, frozenset({'x', 'z'}))
++
++        with self.assertRaises(NameError):
++            A.__annotations__
++
++        import annotationlib
++        self.assertEqual(
++            A.__annotate__(annotationlib.Format.STRING),
++            {'x': 'NotRequired[undefined]', 'y': 'ReadOnly[undefined]',
++             'z': 'Required[undefined]'},
++        )
++
++
+ class AnnotatedTests(BaseTestCase):
+ 
+     def test_repr(self):
+@@ -8956,7 +9008,7 @@ class Y(Generic[Tx]):
+         self.assertEqual(get_args(evaluated_ref1b), (Y[Tx],))
+ 
+         with self.subTest("nested string of TypeVar"):
+-            evaluated_ref2 = 
evaluate_forward_ref(typing.ForwardRef("""Y["Y['Tx']"]"""), locals={"Y": Y})
++            evaluated_ref2 = 
evaluate_forward_ref(typing.ForwardRef("""Y["Y['Tx']"]"""), locals={"Y": Y, 
"Tx": Tx})
+             self.assertEqual(get_origin(evaluated_ref2), Y)
+             self.assertEqual(get_args(evaluated_ref2), (Y[Tx],))
+ 
+--- a/src/typing_extensions.py
++++ b/src/typing_extensions.py
+@@ -14,6 +14,9 @@
+ import typing
+ import warnings
+ 
++if sys.version_info >= (3, 14):
++    import annotationlib
++
+ __all__ = [
+     # Super-special typing primitives.
+     'Any',
+@@ -1018,21 +1021,27 @@ def __new__(cls, name, bases, ns, *, total=True, 
closed=None,
+                 tp_dict.__orig_bases__ = bases
+ 
+             annotations = {}
++            own_annotate = None
+             if "__annotations__" in ns:
+                 own_annotations = ns["__annotations__"]
+-            elif "__annotate__" in ns:
+-                # TODO: Use inspect.VALUE here, and make the annotations 
lazily evaluated
+-                own_annotations = ns["__annotate__"](1)
++            elif sys.version_info >= (3, 14):
++                own_annotate = 
annotationlib.get_annotate_from_class_namespace(ns)
++                if own_annotate is not None:
++                    own_annotations = annotationlib.call_annotate_function(
++                        own_annotate, annotationlib.Format.FORWARDREF, 
owner=tp_dict
++                    )
++                else:
++                    own_annotations = {}
+             else:
+                 own_annotations = {}
+             msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a 
type"
+             if _TAKES_MODULE:
+-                own_annotations = {
++                own_checked_annotations = {
+                     n: typing._type_check(tp, msg, module=tp_dict.__module__)
+                     for n, tp in own_annotations.items()
+                 }
+             else:
+-                own_annotations = {
++                own_checked_annotations = {
+                     n: typing._type_check(tp, msg)
+                     for n, tp in own_annotations.items()
+                 }
+@@ -1045,7 +1054,8 @@ def __new__(cls, name, bases, ns, *, total=True, 
closed=None,
+             for base in bases:
+                 base_dict = base.__dict__
+ 
+-                annotations.update(base_dict.get('__annotations__', {}))
++                if sys.version_info <= (3, 14):
++                    annotations.update(base_dict.get('__annotations__', {}))
+                 required_keys.update(base_dict.get('__required_keys__', ()))
+                 optional_keys.update(base_dict.get('__optional_keys__', ()))
+                 readonly_keys.update(base_dict.get('__readonly_keys__', ()))
+@@ -1055,8 +1065,8 @@ def __new__(cls, name, bases, ns, *, total=True, 
closed=None,
+             # is retained for backwards compatibility, but only for Python
+             # 3.13 and lower.
+             if (closed and sys.version_info < (3, 14)
+-                       and "__extra_items__" in own_annotations):
+-                annotation_type = own_annotations.pop("__extra_items__")
++                       and "__extra_items__" in own_checked_annotations):
++                annotation_type = 
own_checked_annotations.pop("__extra_items__")
+                 qualifiers = set(_get_typeddict_qualifiers(annotation_type))
+                 if Required in qualifiers:
+                     raise TypeError(
+@@ -1070,8 +1080,8 @@ def __new__(cls, name, bases, ns, *, total=True, 
closed=None,
+                     )
+                 extra_items_type = annotation_type
+ 
+-            annotations.update(own_annotations)
+-            for annotation_key, annotation_type in own_annotations.items():
++            annotations.update(own_checked_annotations)
++            for annotation_key, annotation_type in 
own_checked_annotations.items():
+                 qualifiers = set(_get_typeddict_qualifiers(annotation_type))
+ 
+                 if Required in qualifiers:
+@@ -1089,7 +1099,38 @@ def __new__(cls, name, bases, ns, *, total=True, 
closed=None,
+                     mutable_keys.add(annotation_key)
+                     readonly_keys.discard(annotation_key)
+ 
+-            tp_dict.__annotations__ = annotations
++            if sys.version_info >= (3, 14):
++                def __annotate__(format):
++                    annos = {}
++                    for base in bases:
++                        if base is Generic:
++                            continue
++                        base_annotate = base.__annotate__
++                        if base_annotate is None:
++                            continue
++                        base_annos = annotationlib.call_annotate_function(
++                            base.__annotate__, format, owner=base)
++                        annos.update(base_annos)
++                    if own_annotate is not None:
++                        own = annotationlib.call_annotate_function(
++                            own_annotate, format, owner=tp_dict)
++                        if format != annotationlib.Format.STRING:
++                            own = {
++                                n: typing._type_check(tp, msg, 
module=tp_dict.__module__)
++                                for n, tp in own.items()
++                            }
++                    elif format == annotationlib.Format.STRING:
++                        own = 
annotationlib.annotations_to_string(own_annotations)
++                    elif format in (annotationlib.Format.FORWARDREF, 
annotationlib.Format.VALUE):
++                        own = own_checked_annotations
++                    else:
++                        raise NotImplementedError(format)
++                    annos.update(own)
++                    return annos
++
++                tp_dict.__annotate__ = __annotate__
++            else:
++                tp_dict.__annotations__ = annotations
+             tp_dict.__required_keys__ = frozenset(required_keys)
+             tp_dict.__optional_keys__ = frozenset(optional_keys)
+             tp_dict.__readonly_keys__ = frozenset(readonly_keys)
+
+From 83ff33aad4e53ecbd026bfdd683b3c460708e045 Mon Sep 17 00:00:00 2001
+From: Jelle Zijlstra <[email protected]>
+Date: Mon, 5 May 2025 08:03:32 -0700
+Subject: [PATCH 2/5] fix lint
+
+--- a/src/test_typing_extensions.py
++++ b/src/test_typing_extensions.py
+@@ -5176,7 +5176,7 @@ class Y(TypedDict):
+     def test_delayed_type_check(self):
+         # _type_check is also applied later
+         class Z(TypedDict):
+-            a: undefined
++            a: undefined  # noqa: F821
+ 
+         with self.assertRaises(NameError):
+             Z.__annotations__
+@@ -5185,15 +5185,15 @@ class Z(TypedDict):
+         with self.assertRaisesRegex(TypeError, "Plain typing.Final is not 
valid as type argument"):
+             Z.__annotations__
+ 
+-        undefined = None
++        undefined = None  # noqa: F841
+         self.assertEqual(Z.__annotations__, {'a': type(None)})
+ 
+     @skipUnless(TYPING_3_14_0, "Only supported on 3.14")
+     def test_deferred_evaluation(self):
+         class A(TypedDict):
+-            x: NotRequired[undefined]
+-            y: ReadOnly[undefined]
+-            z: Required[undefined]
++            x: NotRequired[undefined]  # noqa: F821
++            y: ReadOnly[undefined]  # noqa: F821
++            z: Required[undefined]  # noqa: F821
+ 
+         self.assertEqual(A.__required_keys__, frozenset({'y', 'z'}))
+         self.assertEqual(A.__optional_keys__, frozenset({'x'}))
+--- a/src/typing_extensions.py
++++ b/src/typing_extensions.py
+@@ -1025,10 +1025,14 @@ def __new__(cls, name, bases, ns, *, total=True, 
closed=None,
+             if "__annotations__" in ns:
+                 own_annotations = ns["__annotations__"]
+             elif sys.version_info >= (3, 14):
+-                own_annotate = 
annotationlib.get_annotate_from_class_namespace(ns)
++                if hasattr(annotationlib, 
"get_annotate_from_class_namespace"):
++                    own_annotate = 
annotationlib.get_annotate_from_class_namespace(ns)
++                else:
++                    # 3.14.0a7 and earlier
++                    own_annotate = ns.get("__annotate__")
+                 if own_annotate is not None:
+                     own_annotations = annotationlib.call_annotate_function(
+-                        own_annotate, annotationlib.Format.FORWARDREF, 
owner=tp_dict
++                        own_annotate, Format.FORWARDREF, owner=tp_dict
+                     )
+                 else:
+                     own_annotations = {}
+@@ -1114,14 +1118,14 @@ def __annotate__(format):
+                     if own_annotate is not None:
+                         own = annotationlib.call_annotate_function(
+                             own_annotate, format, owner=tp_dict)
+-                        if format != annotationlib.Format.STRING:
++                        if format != Format.STRING:
+                             own = {
+                                 n: typing._type_check(tp, msg, 
module=tp_dict.__module__)
+                                 for n, tp in own.items()
+                             }
+-                    elif format == annotationlib.Format.STRING:
++                    elif format == Format.STRING:
+                         own = 
annotationlib.annotations_to_string(own_annotations)
+-                    elif format in (annotationlib.Format.FORWARDREF, 
annotationlib.Format.VALUE):
++                    elif format in (Format.FORWARDREF, Format.VALUE):
+                         own = own_checked_annotations
+                     else:
+                         raise NotImplementedError(format)
+
+From d932665dc4a97d25e06b77063521baf97e89aceb Mon Sep 17 00:00:00 2001
+From: Jelle Zijlstra <[email protected]>
+Date: Mon, 5 May 2025 08:06:31 -0700
+Subject: [PATCH 3/5] fix 3.9/3.10
+
+--- a/src/test_typing_extensions.py
++++ b/src/test_typing_extensions.py
+@@ -5154,9 +5154,9 @@ def test_inline(self):
+ 
+     def test_annotations(self):
+         # _type_check is applied
+-        with self.assertRaisesRegex(TypeError, "Plain typing.Final is not 
valid as type argument"):
++        with self.assertRaisesRegex(TypeError, "Plain typing.Optional is not 
valid as type argument"):
+             class X(TypedDict):
+-                a: Final
++                a: Optional
+ 
+         # _type_convert is applied
+         class Y(TypedDict):
+
+From 34293d775b66bc6c6370b517d11f80719fb4d316 Mon Sep 17 00:00:00 2001
+From: Jelle Zijlstra <[email protected]>
+Date: Mon, 5 May 2025 08:20:26 -0700
+Subject: [PATCH 4/5] fix a7?
+
+--- a/src/test_typing_extensions.py
++++ b/src/test_typing_extensions.py
+@@ -103,6 +103,11 @@
+     runtime_checkable,
+ )
+ 
++if sys.version_info >= (3, 14):
++    from test.support import EqualToForwardRef
++else:
++    EqualToForwardRef = typing.ForwardRef
++
+ NoneType = type(None)
+ T = TypeVar("T")
+ KT = TypeVar("KT")
+@@ -5164,7 +5169,6 @@ class Y(TypedDict):
+             b: "int"
+         if sys.version_info >= (3, 14):
+             import annotationlib
+-            from test.support import EqualToForwardRef
+ 
+             fwdref = EqualToForwardRef('int', module=__name__)
+             self.assertEqual(Y.__annotations__, {'a': type(None), 'b': 
fwdref})
+@@ -6022,7 +6026,7 @@ def test_substitution(self):
+         U2 = Unpack[Ts]
+         self.assertEqual(C2[U1], (str, int, str))
+         self.assertEqual(C2[U2], (str, Unpack[Ts]))
+-        self.assertEqual(C2["U2"], (str, typing.ForwardRef("U2")))
++        self.assertEqual(C2["U2"], (str, EqualToForwardRef("U2")))
+ 
+         if (3, 12, 0) <= sys.version_info < (3, 12, 4):
+             with self.assertRaises(AssertionError):
+@@ -7309,8 +7313,8 @@ def test_or(self):
+             self.assertEqual(X | "x", Union[X, "x"])
+             self.assertEqual("x" | X, Union["x", X])
+             # make sure the order is correct
+-            self.assertEqual(get_args(X | "x"), (X, typing.ForwardRef("x")))
+-            self.assertEqual(get_args("x" | X), (typing.ForwardRef("x"), X))
++            self.assertEqual(get_args(X | "x"), (X, EqualToForwardRef("x")))
++            self.assertEqual(get_args("x" | X), (EqualToForwardRef("x"), X))
+ 
+     def test_union_constrained(self):
+         A = TypeVar('A', str, bytes)
+@@ -8878,7 +8882,7 @@ class X:
+             type_params=None,
+             format=Format.FORWARDREF,
+         )
+-        self.assertEqual(evaluated_ref, typing.ForwardRef("doesnotexist2"))
++        self.assertEqual(evaluated_ref, EqualToForwardRef("doesnotexist2"))
+ 
+     def test_evaluate_with_type_params(self):
+         # Use a T name that is not in globals
+
+From 993ac2fd77b89577a137819ffdb8478d25958742 Mon Sep 17 00:00:00 2001
+From: Jelle Zijlstra <[email protected]>
+Date: Mon, 5 May 2025 08:24:26 -0700
+Subject: [PATCH 5/5] no support
+
+--- a/src/test_typing_extensions.py
++++ b/src/test_typing_extensions.py
+@@ -103,11 +103,6 @@
+     runtime_checkable,
+ )
+ 
+-if sys.version_info >= (3, 14):
+-    from test.support import EqualToForwardRef
+-else:
+-    EqualToForwardRef = typing.ForwardRef
+-
+ NoneType = type(None)
+ T = TypeVar("T")
+ KT = TypeVar("KT")
+@@ -444,6 +439,48 @@ def assertNotIsSubclass(self, cls, class_or_tuple, 
msg=None):
+             raise self.failureException(message)
+ 
+ 
++class EqualToForwardRef:
++    """Helper to ease use of annotationlib.ForwardRef in tests.
++
++    This checks only attributes that can be set using the constructor.
++
++    """
++
++    def __init__(
++        self,
++        arg,
++        *,
++        module=None,
++        owner=None,
++        is_class=False,
++    ):
++        self.__forward_arg__ = arg
++        self.__forward_is_class__ = is_class
++        self.__forward_module__ = module
++        self.__owner__ = owner
++
++    def __eq__(self, other):
++        if not isinstance(other, (EqualToForwardRef, typing.ForwardRef)):
++            return NotImplemented
++        if sys.version_info >= (3, 14) and self.__owner__ != other.__owner__:
++            return False
++        return (
++            self.__forward_arg__ == other.__forward_arg__
++            and self.__forward_module__ == other.__forward_module__
++            and self.__forward_is_class__ == other.__forward_is_class__
++        )
++
++    def __repr__(self):
++        extra = []
++        if self.__forward_module__ is not None:
++            extra.append(f", module={self.__forward_module__!r}")
++        if self.__forward_is_class__:
++            extra.append(", is_class=True")
++        if sys.version_info >= (3, 14) and self.__owner__ is not None:
++            extra.append(f", owner={self.__owner__!r}")
++        return f"EqualToForwardRef({self.__forward_arg__!r}{''.join(extra)})"
++
++
+ class Employee:
+     pass
+ 
+--- a/src/test_typing_extensions.py
++++ b/src/test_typing_extensions.py
+@@ -8957,13 +8957,6 @@ class TestEvaluateForwardRefs(BaseTestCase):
+         obj = object()
+         self.assertIs(evaluate_forward_ref(typing.ForwardRef("int"), 
globals={"int": obj}), obj)
+ 
+-    def test_fwdref_value_is_cached(self):
+-        fr = typing.ForwardRef("hello")
+-        with self.assertRaises(NameError):
+-            evaluate_forward_ref(fr)
+-        self.assertIs(evaluate_forward_ref(fr, globals={"hello": str}), str)
+-        self.assertIs(evaluate_forward_ref(fr), str)
+-
+     @skipUnless(TYPING_3_9_0, "Needs PEP 585 support")
+     def test_fwdref_with_owner(self):
+         self.assertEqual(

Reply via email to