From 32dde8e38975df88336107b112300483325010ef Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 1 Apr 2025 08:26:52 -0700 Subject: [PATCH 1/3] Fix test failures on Python 3.14 --- src/test_typing_extensions.py | 26 ++++++++++++++++++-------- src/typing_extensions.py | 7 +++++-- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/test_typing_extensions.py b/src/test_typing_extensions.py index da4e3e44..6e4e6d5e 100644 --- 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), diff --git a/src/typing_extensions.py b/src/typing_extensions.py index 8333d890..a1165f50 100644 --- 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 Date: Tue, 1 Apr 2025 08:31:01 -0700 Subject: [PATCH 2/3] test & lint --- src/test_typing_extensions.py | 17 +++++++++++------ src/typing_extensions.py | 4 +++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/test_typing_extensions.py b/src/test_typing_extensions.py index 6e4e6d5e..9387ed11 100644 --- 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()), diff --git a/src/typing_extensions.py b/src/typing_extensions.py index a1165f50..1e73e618 100644 --- 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 Date: Thu, 10 Apr 2025 07:09:20 -0700 Subject: [PATCH 3/3] Update src/test_typing_extensions.py --- src/test_typing_extensions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test_typing_extensions.py b/src/test_typing_extensions.py index 60c1a943..72713589 100644 --- 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"},