Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit8f2fb7d

Browse files
gh-99344,gh-99379,gh-99382: Fix issues in substitution of ParamSpec and TypeVarTuple (GH-99412)
* Fix substitution of TypeVarTuple and ParamSpec together in user generics.* Fix substitution of ParamSpec followed by TypeVarTuple in generic aliases.* Check the number of arguments in substitution in user generics containing a TypeVarTuple and one or more TypeVar.
1 parent1d1bb95 commit8f2fb7d

File tree

5 files changed

+117
-41
lines changed

5 files changed

+117
-41
lines changed

‎Lib/test/test_typing.py‎

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,20 +772,42 @@ class C(Generic[*Ts]): pass
772772
('generic[*Ts]','[*Ts]','generic[*Ts]'),
773773
('generic[*Ts]','[T, *Ts]','generic[T, *Ts]'),
774774
('generic[*Ts]','[*Ts, T]','generic[*Ts, T]'),
775+
('generic[T, *Ts]','[()]','TypeError'),
775776
('generic[T, *Ts]','[int]','generic[int]'),
776777
('generic[T, *Ts]','[int, str]','generic[int, str]'),
777778
('generic[T, *Ts]','[int, str, bool]','generic[int, str, bool]'),
779+
('generic[list[T], *Ts]','[()]','TypeError'),
778780
('generic[list[T], *Ts]','[int]','generic[list[int]]'),
779781
('generic[list[T], *Ts]','[int, str]','generic[list[int], str]'),
780782
('generic[list[T], *Ts]','[int, str, bool]','generic[list[int], str, bool]'),
781783

784+
('generic[*Ts, T]','[()]','TypeError'),
782785
('generic[*Ts, T]','[int]','generic[int]'),
783786
('generic[*Ts, T]','[int, str]','generic[int, str]'),
784787
('generic[*Ts, T]','[int, str, bool]','generic[int, str, bool]'),
788+
('generic[*Ts, list[T]]','[()]','TypeError'),
785789
('generic[*Ts, list[T]]','[int]','generic[list[int]]'),
786790
('generic[*Ts, list[T]]','[int, str]','generic[int, list[str]]'),
787791
('generic[*Ts, list[T]]','[int, str, bool]','generic[int, str, list[bool]]'),
788792

793+
('generic[T1, T2, *Ts]','[()]','TypeError'),
794+
('generic[T1, T2, *Ts]','[int]','TypeError'),
795+
('generic[T1, T2, *Ts]','[int, str]','generic[int, str]'),
796+
('generic[T1, T2, *Ts]','[int, str, bool]','generic[int, str, bool]'),
797+
('generic[T1, T2, *Ts]','[int, str, bool, bytes]','generic[int, str, bool, bytes]'),
798+
799+
('generic[*Ts, T1, T2]','[()]','TypeError'),
800+
('generic[*Ts, T1, T2]','[int]','TypeError'),
801+
('generic[*Ts, T1, T2]','[int, str]','generic[int, str]'),
802+
('generic[*Ts, T1, T2]','[int, str, bool]','generic[int, str, bool]'),
803+
('generic[*Ts, T1, T2]','[int, str, bool, bytes]','generic[int, str, bool, bytes]'),
804+
805+
('generic[T1, *Ts, T2]','[()]','TypeError'),
806+
('generic[T1, *Ts, T2]','[int]','TypeError'),
807+
('generic[T1, *Ts, T2]','[int, str]','generic[int, str]'),
808+
('generic[T1, *Ts, T2]','[int, str, bool]','generic[int, str, bool]'),
809+
('generic[T1, *Ts, T2]','[int, str, bool, bytes]','generic[int, str, bool, bytes]'),
810+
789811
('generic[T, *Ts]','[*tuple_type[int, ...]]','generic[int, *tuple_type[int, ...]]'),
790812
('generic[T, *Ts]','[str, *tuple_type[int, ...]]','generic[str, *tuple_type[int, ...]]'),
791813
('generic[T, *Ts]','[*tuple_type[int, ...], str]','generic[int, *tuple_type[int, ...], str]'),
@@ -7241,6 +7263,65 @@ class X(Generic[P, P2]):
72417263
self.assertEqual(G1.__args__, ((int,str), (bytes,)))
72427264
self.assertEqual(G2.__args__, ((int,), (str,bytes)))
72437265

7266+
deftest_typevartuple_and_paramspecs_in_user_generics(self):
7267+
Ts=TypeVarTuple("Ts")
7268+
P=ParamSpec("P")
7269+
7270+
classX(Generic[*Ts,P]):
7271+
f:Callable[P,int]
7272+
g:Tuple[*Ts]
7273+
7274+
G1=X[int, [bytes]]
7275+
self.assertEqual(G1.__args__, (int, (bytes,)))
7276+
G2=X[int,str, [bytes]]
7277+
self.assertEqual(G2.__args__, (int,str, (bytes,)))
7278+
G3=X[[bytes]]
7279+
self.assertEqual(G3.__args__, ((bytes,),))
7280+
G4=X[[]]
7281+
self.assertEqual(G4.__args__, ((),))
7282+
withself.assertRaises(TypeError):
7283+
X[()]
7284+
7285+
classY(Generic[P,*Ts]):
7286+
f:Callable[P,int]
7287+
g:Tuple[*Ts]
7288+
7289+
G1=Y[[bytes],int]
7290+
self.assertEqual(G1.__args__, ((bytes,),int))
7291+
G2=Y[[bytes],int,str]
7292+
self.assertEqual(G2.__args__, ((bytes,),int,str))
7293+
G3=Y[[bytes]]
7294+
self.assertEqual(G3.__args__, ((bytes,),))
7295+
G4=Y[[]]
7296+
self.assertEqual(G4.__args__, ((),))
7297+
withself.assertRaises(TypeError):
7298+
Y[()]
7299+
7300+
deftest_typevartuple_and_paramspecs_in_generic_aliases(self):
7301+
P=ParamSpec('P')
7302+
T=TypeVar('T')
7303+
Ts=TypeVarTuple('Ts')
7304+
7305+
forCinCallable,collections.abc.Callable:
7306+
withself.subTest(generic=C):
7307+
A=C[P,Tuple[*Ts]]
7308+
B=A[[int,str],bytes,float]
7309+
self.assertEqual(B.__args__, (int,str,Tuple[bytes,float]))
7310+
7311+
classX(Generic[T,P]):
7312+
pass
7313+
7314+
A=X[Tuple[*Ts],P]
7315+
B=A[bytes,float, [int,str]]
7316+
self.assertEqual(B.__args__, (Tuple[bytes,float], (int,str,)))
7317+
7318+
classY(Generic[P,T]):
7319+
pass
7320+
7321+
A=Y[P,Tuple[*Ts]]
7322+
B=A[[int,str],bytes,float]
7323+
self.assertEqual(B.__args__, ((int,str,),Tuple[bytes,float]))
7324+
72447325
deftest_var_substitution(self):
72457326
T=TypeVar("T")
72467327
P=ParamSpec("P")

‎Lib/typing.py‎

Lines changed: 30 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -284,25 +284,6 @@ def _unpack_args(args):
284284
newargs.append(arg)
285285
returnnewargs
286286

287-
def_prepare_paramspec_params(cls,params):
288-
"""Prepares the parameters for a Generic containing ParamSpec
289-
variables (internal helper).
290-
"""
291-
# Special case where Z[[int, str, bool]] == Z[int, str, bool] in PEP 612.
292-
if (len(cls.__parameters__)==1
293-
andparamsandnot_is_param_expr(params[0])):
294-
assertisinstance(cls.__parameters__[0],ParamSpec)
295-
return (params,)
296-
else:
297-
_check_generic(cls,params,len(cls.__parameters__))
298-
_params= []
299-
# Convert lists to tuples to help other libraries cache the results.
300-
forp,tvarinzip(params,cls.__parameters__):
301-
ifisinstance(tvar,ParamSpec)andisinstance(p,list):
302-
p=tuple(p)
303-
_params.append(p)
304-
returntuple(_params)
305-
306287
def_deduplicate(params):
307288
# Weed out strict duplicates, preserving the first of each occurrence.
308289
all_params=set(params)
@@ -1238,7 +1219,18 @@ def __typing_subst__(self, arg):
12381219
returnarg
12391220

12401221
def__typing_prepare_subst__(self,alias,args):
1241-
return_prepare_paramspec_params(alias,args)
1222+
params=alias.__parameters__
1223+
i=params.index(self)
1224+
ifi>=len(args):
1225+
raiseTypeError(f"Too few arguments for{alias}")
1226+
# Special case where Z[[int, str, bool]] == Z[int, str, bool] in PEP 612.
1227+
iflen(params)==1andnot_is_param_expr(args[0]):
1228+
asserti==0
1229+
args= (args,)
1230+
# Convert lists to tuples to help other libraries cache the results.
1231+
elifisinstance(args[i],list):
1232+
args= (*args[:i],tuple(args[i]),*args[i+1:])
1233+
returnargs
12421234

12431235
def_is_dunder(attr):
12441236
returnattr.startswith('__')andattr.endswith('__')
@@ -1801,23 +1793,13 @@ def __class_getitem__(cls, params):
18011793
ifnotisinstance(params,tuple):
18021794
params= (params,)
18031795

1804-
ifnotparams:
1805-
# We're only ok with `params` being empty if the class's only type
1806-
# parameter is a `TypeVarTuple` (which can contain zero types).
1807-
class_params=getattr(cls,"__parameters__",None)
1808-
only_class_parameter_is_typevartuple= (
1809-
class_paramsisnotNone
1810-
andlen(class_params)==1
1811-
andisinstance(class_params[0],TypeVarTuple)
1812-
)
1813-
ifnotonly_class_parameter_is_typevartuple:
1814-
raiseTypeError(
1815-
f"Parameter list to{cls.__qualname__}[...] cannot be empty"
1816-
)
1817-
18181796
params=tuple(_type_convert(p)forpinparams)
18191797
ifclsin (Generic,Protocol):
18201798
# Generic and Protocol can only be subscripted with unique type variables.
1799+
ifnotparams:
1800+
raiseTypeError(
1801+
f"Parameter list to{cls.__qualname__}[...] cannot be empty"
1802+
)
18211803
ifnotall(_is_typevar_like(p)forpinparams):
18221804
raiseTypeError(
18231805
f"Parameters to{cls.__name__}[...] must all be type variables "
@@ -1827,13 +1809,20 @@ def __class_getitem__(cls, params):
18271809
f"Parameters to{cls.__name__}[...] must all be unique")
18281810
else:
18291811
# Subscripting a regular Generic subclass.
1830-
ifany(isinstance(t,ParamSpec)fortincls.__parameters__):
1831-
params=_prepare_paramspec_params(cls,params)
1832-
elifnotany(isinstance(p,TypeVarTuple)forpincls.__parameters__):
1833-
# We only run this if there are no TypeVarTuples, because we
1834-
# don't check variadic generic arity at runtime (to reduce
1835-
# complexity of typing.py).
1836-
_check_generic(cls,params,len(cls.__parameters__))
1812+
forparamincls.__parameters__:
1813+
prepare=getattr(param,'__typing_prepare_subst__',None)
1814+
ifprepareisnotNone:
1815+
params=prepare(cls,params)
1816+
_check_generic(cls,params,len(cls.__parameters__))
1817+
1818+
new_args= []
1819+
forparam,new_arginzip(cls.__parameters__,params):
1820+
ifisinstance(param,TypeVarTuple):
1821+
new_args.extend(new_arg)
1822+
else:
1823+
new_args.append(new_arg)
1824+
params=tuple(new_args)
1825+
18371826
return_GenericAlias(cls,params,
18381827
_paramspec_tvars=True)
18391828

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix substitution of:class:`~typing.TypeVarTuple` and
2+
:class:`~typing.ParamSpec` together in user generics.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix substitution of:class:`~typing.ParamSpec` followed by
2+
:class:`~typing.TypeVarTuple` in generic aliases.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Check the number of arguments in substitution in user generics containing a
2+
:class:`~typing.TypeVarTuple` and one or more:class:`~typing.TypeVar`.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp