Skip to content

Commit 48a5fe0

Browse files
Fix tests on Python 3.11 (#1139)
- Defer to the PEP 646 implementation in typing.py on 3.11 - Adjust some tests accordingly. Noted a bug in python/cpython#32341 (comment) - typing._type_check() is more lenient in 3.11 and no longer rejects ints - The representation of the empty tuple type changed Tests pass for me on a 3.11 build from today now.
1 parent af2ebf7 commit 48a5fe0

File tree

3 files changed

+102
-79
lines changed

3 files changed

+102
-79
lines changed

CHANGELOG

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Unreleased
22

3+
- Re-export `typing.Unpack` and `typing.TypeVarTuple` on Python 3.11.
34
- Add `ParamSpecArgs` and `ParamSpecKwargs` to `__all__`.
45
- Improve "accepts only single type" error messages.
56
- Improve the distributed package. Patch by Marc Mueller (@cdce8p).

src/test_typing_extensions.py

+39-22
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
# version of the typing module.
3333
TYPING_3_8_0 = sys.version_info[:3] >= (3, 8, 0)
3434
TYPING_3_10_0 = sys.version_info[:3] >= (3, 10, 0)
35+
36+
# 3.11 makes runtime type checks (_type_check) more lenient.
3537
TYPING_3_11_0 = sys.version_info[:3] >= (3, 11, 0)
3638

3739

@@ -157,8 +159,9 @@ def test_exception(self):
157159
class ClassVarTests(BaseTestCase):
158160

159161
def test_basics(self):
160-
with self.assertRaises(TypeError):
161-
ClassVar[1]
162+
if not TYPING_3_11_0:
163+
with self.assertRaises(TypeError):
164+
ClassVar[1]
162165
with self.assertRaises(TypeError):
163166
ClassVar[int, str]
164167
with self.assertRaises(TypeError):
@@ -201,8 +204,9 @@ def test_no_isinstance(self):
201204
class FinalTests(BaseTestCase):
202205

203206
def test_basics(self):
204-
with self.assertRaises(TypeError):
205-
Final[1]
207+
if not TYPING_3_11_0:
208+
with self.assertRaises(TypeError):
209+
Final[1]
206210
with self.assertRaises(TypeError):
207211
Final[int, str]
208212
with self.assertRaises(TypeError):
@@ -245,8 +249,9 @@ def test_no_isinstance(self):
245249
class RequiredTests(BaseTestCase):
246250

247251
def test_basics(self):
248-
with self.assertRaises(TypeError):
249-
Required[1]
252+
if not TYPING_3_11_0:
253+
with self.assertRaises(TypeError):
254+
Required[1]
250255
with self.assertRaises(TypeError):
251256
Required[int, str]
252257
with self.assertRaises(TypeError):
@@ -289,8 +294,9 @@ def test_no_isinstance(self):
289294
class NotRequiredTests(BaseTestCase):
290295

291296
def test_basics(self):
292-
with self.assertRaises(TypeError):
293-
NotRequired[1]
297+
if not TYPING_3_11_0:
298+
with self.assertRaises(TypeError):
299+
NotRequired[1]
294300
with self.assertRaises(TypeError):
295301
NotRequired[int, str]
296302
with self.assertRaises(TypeError):
@@ -738,7 +744,10 @@ class C(Generic[T]): pass
738744
self.assertEqual(get_args(Union[int, Callable[[Tuple[T, ...]], str]]),
739745
(int, Callable[[Tuple[T, ...]], str]))
740746
self.assertEqual(get_args(Tuple[int, ...]), (int, ...))
741-
self.assertEqual(get_args(Tuple[()]), ((),))
747+
if TYPING_3_11_0:
748+
self.assertEqual(get_args(Tuple[()]), ())
749+
else:
750+
self.assertEqual(get_args(Tuple[()]), ((),))
742751
self.assertEqual(get_args(Annotated[T, 'one', 2, ['three']]), (T, 'one', 2, ['three']))
743752
self.assertEqual(get_args(List), ())
744753
self.assertEqual(get_args(Tuple), ())
@@ -1731,10 +1740,12 @@ def test_typeddict_errors(self):
17311740
isinstance(jim, Emp)
17321741
with self.assertRaises(TypeError):
17331742
issubclass(dict, Emp)
1734-
with self.assertRaises(TypeError):
1735-
TypedDict('Hi', x=1)
1736-
with self.assertRaises(TypeError):
1737-
TypedDict('Hi', [('x', int), ('y', 1)])
1743+
1744+
if not TYPING_3_11_0:
1745+
with self.assertRaises(TypeError):
1746+
TypedDict('Hi', x=1)
1747+
with self.assertRaises(TypeError):
1748+
TypedDict('Hi', [('x', int), ('y', 1)])
17381749
with self.assertRaises(TypeError):
17391750
TypedDict('Hi', [('x', int)], y=int)
17401751

@@ -2313,11 +2324,12 @@ def test_invalid_uses(self):
23132324
):
23142325
Concatenate[P, T]
23152326

2316-
with self.assertRaisesRegex(
2317-
TypeError,
2318-
'each arg must be a type',
2319-
):
2320-
Concatenate[1, P]
2327+
if not TYPING_3_11_0:
2328+
with self.assertRaisesRegex(
2329+
TypeError,
2330+
'each arg must be a type',
2331+
):
2332+
Concatenate[1, P]
23212333

23222334
def test_basic_introspection(self):
23232335
P = ParamSpec('P')
@@ -2497,7 +2509,10 @@ def test_basic_plain(self):
24972509

24982510
def test_repr(self):
24992511
Ts = TypeVarTuple('Ts')
2500-
self.assertEqual(repr(Unpack[Ts]), 'typing_extensions.Unpack[Ts]')
2512+
if TYPING_3_11_0:
2513+
self.assertEqual(repr(Unpack[Ts]), '*Ts')
2514+
else:
2515+
self.assertEqual(repr(Unpack[Ts]), 'typing_extensions.Unpack[Ts]')
25012516

25022517
def test_cannot_subclass_vars(self):
25032518
with self.assertRaises(TypeError):
@@ -2572,8 +2587,10 @@ class C(Generic[T1, T2, Unpack[Ts]]): pass
25722587
self.assertEqual(C[int, str].__args__, (int, str))
25732588
self.assertEqual(C[int, str, float].__args__, (int, str, float))
25742589
self.assertEqual(C[int, str, float, bool].__args__, (int, str, float, bool))
2575-
with self.assertRaises(TypeError):
2576-
C[int]
2590+
# TODO This should probably also fail on 3.11, pending changes to CPython.
2591+
if not TYPING_3_11_0:
2592+
with self.assertRaises(TypeError):
2593+
C[int]
25772594

25782595

25792596
class TypeVarTupleTests(BaseTestCase):
@@ -2617,7 +2634,7 @@ def test_args_and_parameters(self):
26172634
Ts = TypeVarTuple('Ts')
26182635

26192636
t = Tuple[tuple(Ts)]
2620-
self.assertEqual(t.__args__, (Ts.__unpacked__,))
2637+
self.assertEqual(t.__args__, (Unpack[Ts],))
26212638
self.assertEqual(t.__parameters__, (Ts,))
26222639

26232640

src/typing_extensions.py

+62-57
Original file line numberDiff line numberDiff line change
@@ -1673,7 +1673,9 @@ class Movie(TypedDict):
16731673
""")
16741674

16751675

1676-
if sys.version_info[:2] >= (3, 9):
1676+
if hasattr(typing, "Unpack"): # 3.11+
1677+
Unpack = typing.Unpack
1678+
elif sys.version_info[:2] >= (3, 9):
16771679
class _UnpackSpecialForm(typing._SpecialForm, _root=True):
16781680
def __repr__(self):
16791681
return 'typing_extensions.' + self._name
@@ -1729,84 +1731,87 @@ def _is_unpack(obj):
17291731
return isinstance(obj, _UnpackAlias)
17301732

17311733

1732-
class TypeVarTuple:
1733-
"""Type variable tuple.
1734+
if hasattr(typing, "TypeVarTuple"): # 3.11+
1735+
TypeVarTuple = typing.TypeVarTuple
1736+
else:
1737+
class TypeVarTuple:
1738+
"""Type variable tuple.
17341739
1735-
Usage::
1740+
Usage::
17361741
1737-
Ts = TypeVarTuple('Ts')
1742+
Ts = TypeVarTuple('Ts')
17381743
1739-
In the same way that a normal type variable is a stand-in for a single
1740-
type such as ``int``, a type variable *tuple* is a stand-in for a *tuple* type such as
1741-
``Tuple[int, str]``.
1744+
In the same way that a normal type variable is a stand-in for a single
1745+
type such as ``int``, a type variable *tuple* is a stand-in for a *tuple*
1746+
type such as ``Tuple[int, str]``.
17421747
1743-
Type variable tuples can be used in ``Generic`` declarations.
1744-
Consider the following example::
1748+
Type variable tuples can be used in ``Generic`` declarations.
1749+
Consider the following example::
17451750
1746-
class Array(Generic[*Ts]): ...
1751+
class Array(Generic[*Ts]): ...
17471752
1748-
The ``Ts`` type variable tuple here behaves like ``tuple[T1, T2]``,
1749-
where ``T1`` and ``T2`` are type variables. To use these type variables
1750-
as type parameters of ``Array``, we must *unpack* the type variable tuple using
1751-
the star operator: ``*Ts``. The signature of ``Array`` then behaves
1752-
as if we had simply written ``class Array(Generic[T1, T2]): ...``.
1753-
In contrast to ``Generic[T1, T2]``, however, ``Generic[*Shape]`` allows
1754-
us to parameterise the class with an *arbitrary* number of type parameters.
1753+
The ``Ts`` type variable tuple here behaves like ``tuple[T1, T2]``,
1754+
where ``T1`` and ``T2`` are type variables. To use these type variables
1755+
as type parameters of ``Array``, we must *unpack* the type variable tuple using
1756+
the star operator: ``*Ts``. The signature of ``Array`` then behaves
1757+
as if we had simply written ``class Array(Generic[T1, T2]): ...``.
1758+
In contrast to ``Generic[T1, T2]``, however, ``Generic[*Shape]`` allows
1759+
us to parameterise the class with an *arbitrary* number of type parameters.
17551760
1756-
Type variable tuples can be used anywhere a normal ``TypeVar`` can.
1757-
This includes class definitions, as shown above, as well as function
1758-
signatures and variable annotations::
1761+
Type variable tuples can be used anywhere a normal ``TypeVar`` can.
1762+
This includes class definitions, as shown above, as well as function
1763+
signatures and variable annotations::
17591764
1760-
class Array(Generic[*Ts]):
1765+
class Array(Generic[*Ts]):
17611766
1762-
def __init__(self, shape: Tuple[*Ts]):
1763-
self._shape: Tuple[*Ts] = shape
1767+
def __init__(self, shape: Tuple[*Ts]):
1768+
self._shape: Tuple[*Ts] = shape
17641769
1765-
def get_shape(self) -> Tuple[*Ts]:
1766-
return self._shape
1770+
def get_shape(self) -> Tuple[*Ts]:
1771+
return self._shape
17671772
1768-
shape = (Height(480), Width(640))
1769-
x: Array[Height, Width] = Array(shape)
1770-
y = abs(x) # Inferred type is Array[Height, Width]
1771-
z = x + x # ... is Array[Height, Width]
1772-
x.get_shape() # ... is tuple[Height, Width]
1773+
shape = (Height(480), Width(640))
1774+
x: Array[Height, Width] = Array(shape)
1775+
y = abs(x) # Inferred type is Array[Height, Width]
1776+
z = x + x # ... is Array[Height, Width]
1777+
x.get_shape() # ... is tuple[Height, Width]
17731778
1774-
"""
1779+
"""
17751780

1776-
# Trick Generic __parameters__.
1777-
__class__ = typing.TypeVar
1781+
# Trick Generic __parameters__.
1782+
__class__ = typing.TypeVar
17781783

1779-
def __iter__(self):
1780-
yield self.__unpacked__
1784+
def __iter__(self):
1785+
yield self.__unpacked__
17811786

1782-
def __init__(self, name):
1783-
self.__name__ = name
1787+
def __init__(self, name):
1788+
self.__name__ = name
17841789

1785-
# for pickling:
1786-
try:
1787-
def_mod = sys._getframe(1).f_globals.get('__name__', '__main__')
1788-
except (AttributeError, ValueError):
1789-
def_mod = None
1790-
if def_mod != 'typing_extensions':
1791-
self.__module__ = def_mod
1790+
# for pickling:
1791+
try:
1792+
def_mod = sys._getframe(1).f_globals.get('__name__', '__main__')
1793+
except (AttributeError, ValueError):
1794+
def_mod = None
1795+
if def_mod != 'typing_extensions':
1796+
self.__module__ = def_mod
17921797

1793-
self.__unpacked__ = Unpack[self]
1798+
self.__unpacked__ = Unpack[self]
17941799

1795-
def __repr__(self):
1796-
return self.__name__
1800+
def __repr__(self):
1801+
return self.__name__
17971802

1798-
def __hash__(self):
1799-
return object.__hash__(self)
1803+
def __hash__(self):
1804+
return object.__hash__(self)
18001805

1801-
def __eq__(self, other):
1802-
return self is other
1806+
def __eq__(self, other):
1807+
return self is other
18031808

1804-
def __reduce__(self):
1805-
return self.__name__
1809+
def __reduce__(self):
1810+
return self.__name__
18061811

1807-
def __init_subclass__(self, *args, **kwds):
1808-
if '_root' not in kwds:
1809-
raise TypeError("Cannot subclass special typing classes")
1812+
def __init_subclass__(self, *args, **kwds):
1813+
if '_root' not in kwds:
1814+
raise TypeError("Cannot subclass special typing classes")
18101815

18111816

18121817
if hasattr(typing, "reveal_type"):

0 commit comments

Comments
 (0)