Skip to content

Commit 9727e2a

Browse files
cast list to tuple done, loosened type checks for Generic
1 parent 0a19f34 commit 9727e2a

File tree

2 files changed

+41
-28
lines changed

2 files changed

+41
-28
lines changed

Lib/test/test_typing.py

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,10 +1131,6 @@ class P(PR[int, T], Protocol[T]):
11311131
PR[int]
11321132
with self.assertRaises(TypeError):
11331133
P[int, str]
1134-
with self.assertRaises(TypeError):
1135-
PR[int, 1]
1136-
with self.assertRaises(TypeError):
1137-
PR[int, ClassVar]
11381134

11391135
class C(PR[int, T]): pass
11401136

@@ -1156,8 +1152,6 @@ class P(PR[int, str], Protocol):
11561152
self.assertIsSubclass(P, PR)
11571153
with self.assertRaises(TypeError):
11581154
PR[int]
1159-
with self.assertRaises(TypeError):
1160-
PR[int, 1]
11611155

11621156
class P1(Protocol, Generic[T]):
11631157
def bar(self, x: T) -> str: ...
@@ -1176,8 +1170,6 @@ def bar(self, x: str) -> str:
11761170
return x
11771171

11781172
self.assertIsInstance(Test(), PSub)
1179-
with self.assertRaises(TypeError):
1180-
PR[int, ClassVar]
11811173

11821174
def test_init_called(self):
11831175
T = TypeVar('T')
@@ -4346,25 +4338,30 @@ class X(Generic[T, P]):
43464338
self.assertEqual(G2.__parameters__, (P_2,))
43474339

43484340
# currently raises TypeError for _type_check
4349-
# G3 = X[int, [int, bool]]
4350-
# self.assertEqual(G3.__args__, (int, [int, bool]))
4351-
# self.assertEqual(G3.__parameters__, ())
4352-
4353-
# G4 = X[int, ...]
4354-
# self.assertEqual(G4.__args__, (int, type(Ellipsis)))
4355-
# self.assertEqual(G4.__parameters__, ())
4356-
#
4357-
# class Z(Generic[P]):
4358-
# f: Callable[P, int]
4359-
4360-
# These are valid
4361-
# currently raises TypeError for _type_check
4362-
# G5 = Z[[int, str, bool]]
4341+
G3 = X[int, [int, bool]]
4342+
self.assertEqual(G3.__args__, (int, (int, bool)))
4343+
self.assertEqual(G3.__parameters__, ())
4344+
4345+
G4 = X[int, ...]
4346+
self.assertEqual(G4.__args__, (int, Ellipsis))
4347+
self.assertEqual(G4.__parameters__, ())
4348+
4349+
class Z(Generic[P]):
4350+
f: Callable[P, int]
4351+
4352+
G5 = Z[[int, str, bool]]
4353+
self.assertEqual(G5.__args__, ((int, str, bool),))
4354+
self.assertEqual(G5.__parameters__, ())
4355+
4356+
G6 = Z[int, str, bool]
4357+
self.assertEqual(G6.__args__, ((int, str, bool),))
4358+
self.assertEqual(G6.__parameters__, ())
43634359

4364-
# currently raises TypeError for too many parameters (not enough TypeVars)
4365-
# G6 = Z[int, str, bool]
4366-
# self.assertEqual(G6.__args__, (int, str, bool))
4367-
# self.assertEqual(G6.__parameters__, ())
4360+
# G5 and G6 should be equivalent according to the PEP
4361+
self.assertEqual(G5.__args__, G6.__args__)
4362+
self.assertEqual(G5.__origin__, G6.__origin__)
4363+
self.assertEqual(G5.__parameters__, G6.__parameters__)
4364+
self.assertEqual(G5, G6)
43684365

43694366

43704367
class ConcatenateTests(BaseTestCase):

Lib/typing.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,8 +1127,7 @@ def __class_getitem__(cls, params):
11271127
if not params and cls is not Tuple:
11281128
raise TypeError(
11291129
f"Parameter list to {cls.__qualname__}[...] cannot be empty")
1130-
msg = "Parameters to generic types must be types."
1131-
params = tuple(_type_check(p, msg) for p in params)
1130+
params = tuple(_type_convert(p) for p in params)
11321131
if cls in (Generic, Protocol):
11331132
# Generic and Protocol can only be subscripted with unique type variables.
11341133
if not all(isinstance(p, (TypeVar, ParamSpec)) for p in params):
@@ -1140,6 +1139,23 @@ def __class_getitem__(cls, params):
11401139
f"Parameters to {cls.__name__}[...] must all be unique")
11411140
else:
11421141
# Subscripting a regular Generic subclass.
1142+
1143+
# Code below handles PEP 612 ParamSpec.
1144+
if any(isinstance(t, ParamSpec) for t in cls.__parameters__):
1145+
# Special case where Z[[int, str, bool]] == Z[int, str, bool]
1146+
# in PEP 612.
1147+
if len(cls.__parameters__) == 1 and len(params) > 1:
1148+
params = (params,)
1149+
else:
1150+
_params = []
1151+
# Convert lists to tuples to help other libraries cache the
1152+
# results.
1153+
for p, tvar in zip(params, cls.__parameters__):
1154+
if isinstance(tvar, ParamSpec) and isinstance(p, list):
1155+
p = tuple(p)
1156+
_params.append(p)
1157+
params = tuple(_params)
1158+
11431159
_check_generic(cls, params, len(cls.__parameters__))
11441160
return _GenericAlias(cls, params)
11451161

0 commit comments

Comments
 (0)