Skip to content

Commit ee810d9

Browse files
committed
Adjust tests and cover G5, G6, H9, G10
1 parent 4f715a5 commit ee810d9

File tree

2 files changed

+36
-28
lines changed

2 files changed

+36
-28
lines changed

src/test_typing_extensions.py

+29-28
Original file line numberDiff line numberDiff line change
@@ -5301,7 +5301,6 @@ class Z(Generic[P]):
53015301
class ProtoZ(Protocol[P]):
53025302
pass
53035303

5304-
things = "arguments" if sys.version_info >= (3, 10) else "parameters"
53055304
for klass in Z, ProtoZ:
53065305
with self.subTest(klass=klass.__name__):
53075306
# Note: For 3.10+ __args__ are nested tuples here ((int, ),) instead of (int, )
@@ -5344,13 +5343,20 @@ class ProtoZ(Protocol[P]):
53445343
G6 = klass[int, str, T]
53455344
G8 = klass[Concatenate[T, ...]]
53465345
G9 = klass[Concatenate[T, P_2]]
5347-
G10 = klass[int, Concatenate[str, P]]
53485346

5349-
with self.subTest("Check generic substitution", klass=klass.__name__):
5350-
if sys.version_info < (3, 10):
5351-
self.skipTest("_ConcatenateGenericAlias not subscriptable")
5352-
with self.assertRaisesRegex(TypeError, "Expected a list of types, an ellipsis, ParamSpec, or Concatenate"):
5353-
G9[int, int]
5347+
with self.assertRaisesRegex(TypeError,
5348+
(
5349+
"The last parameter to Concatenate should be a ParamSpec variable or ellipsis."
5350+
if sys.version_info < (3, 10) else
5351+
# from __typing_subst__
5352+
"Expected a list of types, an ellipsis, ParamSpec, or Concatenate"
5353+
)
5354+
):
5355+
G9[int, int]
5356+
5357+
self.assertEqual(G9.__parameters__, (T, P_2))
5358+
with self.assertRaisesRegex(TypeError, f"Too few {things}"):
5359+
G9[int]
53545360

53555361
with self.subTest("Check list as parameter expression", klass=klass.__name__):
53565362
if sys.version_info < (3, 10):
@@ -5359,41 +5365,36 @@ class ProtoZ(Protocol[P]):
53595365
self.assertEqual(G5.__args__, ((int, str, T),))
53605366
H9 = G9[int, [T]]
53615367

5362-
self.assertEqual(G9.__parameters__, (T, P_2))
5363-
with self.assertRaisesRegex(TypeError, f"Too few {things}"):
5364-
G9[int]
53655368

53665369
with self.subTest("Check parametrization", klass=klass.__name__):
5367-
if sys.version_info[:2] == (3, 10):
5368-
self.skipTest("Parameter detection fails in 3.10")
5369-
with self.assertRaisesRegex(TypeError, f"Too few {things}"):
5370-
G9[int] # for python 3.10 this has no parameters
5371-
if sys.version_info >= (3, 10): # skipped above
5372-
self.assertEqual(G5.__parameters__, (T,))
5370+
if sys.version_info >= (3, 10): # only availiable for 3.10+
53735371
self.assertEqual(H9.__parameters__, (T,))
5372+
self.assertEqual(G5.__parameters__, (T,))
53745373
self.assertEqual(G6.__parameters__, (T,))
5375-
self.assertEqual(G8.__parameters__, (T,))
5376-
self.assertEqual(G9.__parameters__, (T, P_2))
53775374

53785375
with self.subTest("Check further substitution", klass=klass.__name__):
5379-
if sys.version_info < (3, 10):
5380-
self.skipTest("_ConcatenateGenericAlias not subscriptable")
5381-
if sys.version_info[:2] == (3, 10):
5382-
self.skipTest("Parameter detection fails in 3.10")
5383-
if (3, 11, 0) <= sys.version_info[:3] < (3, 11, 3):
5384-
self.skipTest("Wrong recursive substitution")
53855376
H1 = G8[int]
53865377
self.assertEqual(H1.__parameters__, ())
53875378
with self.assertRaisesRegex(TypeError, "not a generic class"):
5388-
H1[str] # for python 3.11.0-3 this still has a parameter
5379+
H1[str]
53895380

53905381
H2 = G8[T][int]
53915382
self.assertEqual(H2.__parameters__, ())
53925383
with self.assertRaisesRegex(TypeError, "not a generic class"):
5393-
H2[str] # for python 3.11.0-3 this still has a parameter
5384+
H2[str]
53945385

5386+
# This is an invalid parameter expression but useful for testing correct subsitution
5387+
G10 = klass[int, Concatenate[str, P]]
5388+
with self.subTest("Check invalid form substitution"):
5389+
self.assertEqual(G10.__parameters__, (P, ))
5390+
if sys.version_info < (3, 9):
5391+
self.skipTest("3.8 typing._type_subst does not support this substitution process")
53955392
H3 = G10[int]
5396-
self.assertEqual(H3.__args__, ((int, (str, int)),))
5393+
if (3, 10) <= sys.version_info < (3, 11, 3):
5394+
self.skipTest("3.10-3.11.2 does not substitute Concatenate here")
5395+
self.assertEqual(H3.__parameters__, ())
5396+
H3args = H3.__args__[0] if sys.version_info >= (3, 10) else H3.__args__
5397+
self.assertEqual(H3args, (int, (str, int)))
53975398

53985399
def test_pickle(self):
53995400
global P, P_co, P_contra, P_default
@@ -5591,6 +5592,7 @@ def test_substitution(self):
55915592
U2 = Unpack[Ts]
55925593
self.assertEqual(C2[U1], (str, int, str))
55935594
self.assertEqual(C2[U2], (str, Unpack[Ts]))
5595+
self.assertEqual(C2["U2"], (str, typing.ForwardRef("U2")))
55945596

55955597
if (3, 12, 0) <= sys.version_info < (3, 12, 4):
55965598
with self.assertRaises(AssertionError):
@@ -5602,7 +5604,6 @@ def test_substitution(self):
56025604
C3 = Concatenate[str, T, P]
56035605
self.assertEqual(C3[int, [bool]], (str, int, bool))
56045606

5605-
56065607
class TypeGuardTests(BaseTestCase):
56075608
def test_basics(self):
56085609
TypeGuard[int] # OK

src/typing_extensions.py

+7
Original file line numberDiff line numberDiff line change
@@ -3309,6 +3309,13 @@ def _collect_type_vars(types, typevar_types=None):
33093309
tvars.append(t)
33103310
if _should_collect_from_parameters(t):
33113311
tvars.extend([t for t in t.__parameters__ if t not in tvars])
3312+
elif isinstance(t, tuple):
3313+
# Collect nested type_vars
3314+
# tuple wrapped by _prepare_paramspec_params(cls, params)
3315+
for x in t:
3316+
for collected in _collect_type_vars([x]):
3317+
if collected not in tvars:
3318+
tvars.append(collected)
33123319
return tuple(tvars)
33133320

33143321
typing._collect_type_vars = _collect_type_vars

0 commit comments

Comments
 (0)