8000 Partial work · python/cpython@900cd40 · GitHub
[go: up one dir, main page]

Skip to content

Commit 900cd40

Browse files
committed
Partial work
1 parent 71a348b commit 900cd40

File tree

2 files changed

+34
-23
lines changed

2 files changed

+34
-23
lines changed

Lib/test/test_typing.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ def test_constructor(self):
580580
self.assertIs(T.__bound__, None)
581581

582582

583-
class TypeVarLikeDefaultsTests(BaseTestCase):
583+
class TypeParameterDefaultsTests(BaseTestCase):
584584
def test_typevar(self):
585585
T = TypeVar('T', default=int)
586586
self.assertEqual(T.__default__, int)
@@ -620,6 +620,12 @@ def test_typevartuple(self):
620620
class A(Generic[Unpack[Ts]]): ...
621621
Alias = Optional[Unpack[Ts]]
622622

623+
def test_typevartuple_specialization(self):
624+
T = TypeVar("T")
625+
Ts = TypeVarTuple('Ts', default=Unpack[Tuple[str, int]])
626+
class A(Generic[T, Unpack[Ts]]): ...
627+
self.assertEqual(A[float].__args__, (float, int, str))
628+
623629
def test_typevartuple_none(self):
624630
U = TypeVarTuple('U')
625631
U_None = TypeVarTuple('U_None', default=None)

Lib/typing.py

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ def _collect_parameters(args):
266266
>>> _collect_parameters((T, Callable[P, T]))
267267
(~T, ~P)
268268
"""
269-
# required TypeVarLike cannot appear after TypeVarLike with default
269+
# required type parameter cannot appear after parameter with default
270270
default_encountered = False
271271
parameters = []
272272
for t in args:
@@ -296,36 +296,32 @@ def _collect_parameters(args):
296296
return tuple(parameters)
297297

298298

299-
def _check_generic(cls, parameters, elen):
299+
def _check_generic_specialization(cls, parameters):
300300
"""Check correct count for parameters of a generic cls (internal helper).
301301
302302
This gives a nice error message in case of count mismatch.
303303
"""
304+
elen = len(cls.__parameters__)
304305
if not elen:
305306
raise TypeError(f"{cls} is not a generic class")
306307
alen = len(parameters)
307308
if alen != elen:
308-
expect_val = elen
309-
if hasattr(cls, "__parameters__"):
310-
parameters = [p for p in cls.__parameters__ if get_origin(p) is not Unpack]
311-
312-
# deal with TypeVarLike defaults
313-
# required TypeVarLikes cannot appear after a defaulted one.
314-
if alen < elen:
315-
# since we validate TypeVarLike default in _collect_type_vars
316-
# or _collect_parameters we can safely check parameters[alen]
317-
if parameters[alen].__default__ is not None:
318-
return
319-
320-
num_default_tv = sum(p.__default__ is not None for p in parameters)
321-
322-
elen -= num_default_tv
323-
324-
expect_val = f"at least {elen}"
309+
# deal with defaults
310+
if alen < elen:
311+
# since we validate defaults in _collect_type_vars
312+
# or _collect_parameters, we can safely check parameters[alen]
313+
if cls.__parameters__[alen].__default__ is not None:
314+
return
315+
316+
elen -= sum(p.__default__ is not None for p in cls.__parameters__)
317+
expect_val = f"at least {elen}"
318+
else:
319+
expect_val = elen
325320

326321
raise TypeError(f"Too {'many' if alen > elen else 'few'} arguments"
327322
f" for {cls}; actual {alen}, expected {expect_val}")
328323

324+
329325
def _unpack_args(args):
330326
newargs = []
331327
for arg in args:
@@ -1115,11 +1111,15 @@ def _typevartuple_prepare_subst(self, alias, args):
11151111
elif left + right > alen:
11161112
raise TypeError(f"Too few arguments for {alias};"
11171113
f" actual {alen}, expected at least {plen-1}")
1114+
if left == alen - right and self.__default__ is not None:
1115+
replacement = self.__default__
1116+
else:
1117+
replacement = tuple(args[left: alen - right])
11181118

11191119
return (
11201120
*args[:left],
11211121
*([fillarg]*(typevartuple_index - left)),
1122-
tuple(args[left: alen - right]),
1122+
replacement,
11231123
*([fillarg]*(plen - right - left - typevartuple_index - 1)),
11241124
*args[alen - right:],
11251125
)
@@ -1185,7 +1185,7 @@ def _generic_class_getitem(cls, params):
11851185
prepare = getattr(param, '__typing_prepare_subst__', None)
11861186
if prepare is not None:
11871187
params = prepare(cls, params)
1188-
_check_generic(cls, params, len(cls.__parameters__))
1188+
_check_generic_specialization(cls, params)
11891189

11901190
new_args = []
11911191
for param, new_arg in zip(cls.__parameters__, params):
@@ -1578,7 +1578,12 @@ def __getitem__(self, params):
15781578
params = (params,)
15791579
msg = "Parameters to generic types must be types."
15801580
params = tuple(_type_check(p, msg) for p in params)
1581-
_check_generic(self, params, self._nparams)
1581+
if not self._nparams:
1582+
raise TypeError(f"{self} is not a generic class")
1583+
alen = len(params)
1584+
if alen != self._nparams:
1585+
raise TypeError(f"Too {'many' if alen > self._nparams else 'few'} arguments for {self};"
1586+
f" actual {alen}, expected {self._nparams}")
15821587
return self.copy_with(params)
15831588

15841589
def copy_with(self, params):

0 commit comments

Comments
 (0)
0