Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 47 additions & 15 deletions src/test_typing_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@

TYPING_3_14_0 = sys.version_info[:3] >= (3, 14, 0)

TYPING_3_15_0 = sys.version_info[:3] >= (3, 15, 0)

TYPING_3_15_0_BETA_1 = sys.version_info[:5] == (3, 15, 0, 'beta', 1)

# https://github.com/python/cpython/pull/27017 was backported into some 3.9 and 3.10
# versions, but not all
HAS_FORWARD_MODULE = "module" in inspect.signature(typing._type_check).parameters
Expand Down Expand Up @@ -1761,8 +1765,6 @@ def test_annotation_and_optional_default(self):
Optional[annotation] : Optional[annotation],
Union[str, None, str] : Optional[str],
Unpack[Tuple[int, None]]: Unpack[Tuple[int, None]],
# Note: A starred *Ts will use typing.Unpack in 3.11+ see Issue #485
Unpack[Ts] : Unpack[Ts],
}
# contains a ForwardRef, TypeVar(~prefix) or no expression
do_not_stringify_cases = {
Expand All @@ -1779,6 +1781,12 @@ def test_annotation_and_optional_default(self):
Union["annotation", T_default] : Union[annotation, T_default],
Annotated["annotation", "nested"] : Annotated[Union[int, None], "data", "nested"],
}
# Note: A starred *Ts will use typing.Unpack in 3.11+ see Issue #485
if TYPING_3_15_0:
# The repr is typing.Unpack[~Ts], which cannot be evaluated.
do_not_stringify_cases[Unpack[Ts]] = Unpack[Ts]
else:
cases[Unpack[Ts]] = Unpack[Ts]
if TYPING_3_10_0: # cannot construct UnionTypes before 3.10
do_not_stringify_cases["str | NoneAlias | StrAlias"] = str | None
cases[str | None] = Optional[str]
Expand Down Expand Up @@ -6599,10 +6607,16 @@ def test_basic_plain(self):
with self.assertRaises(TypeError):
Unpack()

@skipIf(TYPING_3_15_0, "repr changed in 3.15")
def test_repr(self):
Ts = TypeVarTuple('Ts')
self.assertEqual(repr(Unpack[Ts]), f'{Unpack.__module__}.Unpack[Ts]')

@skipUnless(TYPING_3_15_0, "repr changed in 3.15")
def test_repr_py315(self):
Ts = TypeVarTuple('Ts')
self.assertEqual(repr(Unpack[Ts]), f'{Unpack.__module__}.Unpack[~Ts]')

def test_cannot_subclass_vars(self):
with self.assertRaises(TypeError):
class V(Unpack[TypeVarTuple('Ts')]):
Expand Down Expand Up @@ -6797,10 +6811,16 @@ def test_basic_plain(self):
Ys = TypeVarTuple('Ys')
self.assertNotEqual(Xs, Ys)

@skipIf(TYPING_3_15_0, "repr changed in 3.15")
def test_repr(self):
Ts = TypeVarTuple('Ts')
self.assertEqual(repr(Ts), 'Ts')

@skipUnless(TYPING_3_15_0, "repr changed in 3.15")
def test_repr_py315(self):
Ts = TypeVarTuple('Ts')
self.assertEqual(repr(Ts), '~Ts')

def test_no_redefinition(self):
self.assertNotEqual(TypeVarTuple('Ts'), TypeVarTuple('Ts'))

Expand Down Expand Up @@ -7973,7 +7993,6 @@ def test_doc(self):
self.assertIsInstance(self.sentinel_type.__doc__, str)

def test_constructor(self):
self.assertIs(self.sentinel_type, type(self.sentinel_type)())
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't hold true on Python 3.15, and doesn't seem worth having a conditional test for

with self.assertRaises(TypeError):
type(self.sentinel_type)(1)

Expand Down Expand Up @@ -8009,12 +8028,13 @@ def test_repr(self):
class NoExtraItemsTests(SentinelTestsMixin, BaseTestCase):
sentinel_type = NoExtraItems

@skipIf(TYPING_3_15_0, "repr changed in 3.15")
def test_repr(self):
if hasattr(typing, 'NoExtraItems'):
mod_name = 'typing'
else:
mod_name = "typing_extensions"
self.assertEqual(repr(NoExtraItems), f"{mod_name}.NoExtraItems")
self.assertEqual(repr(NoExtraItems), "typing_extensions.NoExtraItems")

@skipUnless(TYPING_3_15_0, "repr changed in 3.15")
def test_repr_py315(self):
self.assertEqual(repr(NoExtraItems), "NoExtraItems")


class TypeVarInferVarianceTests(BaseTestCase):
Expand Down Expand Up @@ -9537,11 +9557,11 @@ def test_name_lookup_without_eval(self):
float,
)
self.assertIs(evaluate_forward_ref(typing.ForwardRef("int"), globals={"int": str}), str)

import builtins

from test import support
with support.swap_attr(builtins, "int", dict):
self.assertIs(evaluate_forward_ref(typing.ForwardRef("int")), dict)
Comment on lines -9542 to -9544
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uv builds of Python don't have the test module available so this test failed for me locally

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just put Codex on fixing the same issue and it decided to do this instead:

@@ -9530,9 +9555,7 @@ class EvaluateForwardRefTests(BaseTestCase):
         )
         self.assertIs(evaluate_forward_ref(typing.ForwardRef("int"), globals={"int": str}), str)
         import builtins
-
-        from test import support
-        with support.swap_attr(builtins, "int", dict):
+        with patch.object(builtins, "int", dict):
             self.assertIs(evaluate_forward_ref(typing.ForwardRef("int")), dict)
 
     def test_nested_strings(self):

Seems simpler?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh that's nice, i forgot about patch.object

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made that change. I wonder what benefit there is to test.support.swap_attr in the CPython test suite over just using mock.patch.object...

with patch.object(builtins, "int", dict):
self.assertIs(evaluate_forward_ref(typing.ForwardRef("int")), dict)

def test_nested_strings(self):
# This variable must have a different name TypeVar
Expand Down Expand Up @@ -9599,10 +9619,9 @@ def test_sentinel_no_repr(self):
self.assertEqual(sentinel_no_repr.__name__, 'sentinel_no_repr')
self.assertEqual(repr(sentinel_no_repr), 'sentinel_no_repr')

def test_sentinel_deprecated_explicit_repr(self):
with self.assertWarnsRegex(DeprecationWarning, r"'repr' parameter is deprecated and will be removed"):
sentinel_explicit_repr = sentinel('sentinel_explicit_repr', repr='explicit_repr')

@skipIf(TYPING_3_15_0_BETA_1, reason="'repr' parameter is not yet available in 3.15.0b1")
def test_sentinel_explicit_repr(self):
sentinel_explicit_repr = sentinel('sentinel_explicit_repr', repr='explicit_repr')
self.assertEqual(repr(sentinel_explicit_repr), 'explicit_repr')

@skipIf(sys.version_info < (3, 10), reason='New unions not available in 3.9')
Expand Down Expand Up @@ -9644,6 +9663,7 @@ def test_sentinel_picklable_anonymous(self):
):
self.assertIs(anonymous_sentinel, pickle.loads(pickle.dumps(anonymous_sentinel, protocol=proto)))

@skipIf(TYPING_3_15_0, reason='Deprecated sentinel APIs were removed in 3.15')
def test_sentinel_deprecated(self):
with self.assertWarnsRegex(DeprecationWarning, r"Subclassing sentinel is deprecated"):
class SentinelSubclass(Sentinel):
Expand All @@ -9656,6 +9676,18 @@ class SentinelSubclass(Sentinel):
with self.assertWarnsRegex(DeprecationWarning, r"Setting attribute 'foo' on sentinel objects is deprecated"):
my_sentinel.foo = "bar"

@skipUnless(TYPING_3_15_0, reason='Deprecated sentinel APIs are available before 3.15')
def test_sentinel_removed_deprecated_apis(self):
with self.assertRaises(TypeError):
class SentinelSubclass(Sentinel):
pass
with self.assertRaises(TypeError):
sentinel()
with self.assertRaises(TypeError):
Sentinel(name="my_sentinel")
with self.assertRaises(AttributeError):
sentinel('my_sentinel').foo = "bar"
Comment on lines +9679 to +9689
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these all cause DeprecationWarnings in the typing_extensions backports but raise exceptions upstream on CPython. The deprecation warnings on Python <=3.14 are tested in the previous test immediately above this



def load_tests(loader, tests, pattern):
import doctest
Expand Down
7 changes: 0 additions & 7 deletions src/typing_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,6 @@ def __init__(
__name = name
if __name is _sentinel_placeholder:
raise TypeError("First parameter 'name' is required")
if repr is not None:
warnings.warn(
"The 'repr' parameter is deprecated "
"and will be removed in Python 3.15.",
DeprecationWarning,
stacklevel=2,
)
Comment on lines -207 to -213
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we added the repr back upstream so I removed the deprecation (python/cpython#149654). The deprecation only exists on main, not on the latest release of typing_extensions, so this doesn't warrant a changelog entry


self.__name__ = __name
self._repr = repr if repr is not None else __name
Expand Down
Loading