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

Commit74920aa

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.(cherry picked from commit8f2fb7d)Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
1 parent5bbf8ed commit74920aa

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
@@ -769,20 +769,42 @@ class C(Generic[*Ts]): pass
769769
('generic[*Ts]','[*Ts]','generic[*Ts]'),
770770
('generic[*Ts]','[T, *Ts]','generic[T, *Ts]'),
771771
('generic[*Ts]','[*Ts, T]','generic[*Ts, T]'),
772+
('generic[T, *Ts]','[()]','TypeError'),
772773
('generic[T, *Ts]','[int]','generic[int]'),
773774
('generic[T, *Ts]','[int, str]','generic[int, str]'),
774775
('generic[T, *Ts]','[int, str, bool]','generic[int, str, bool]'),
776+
('generic[list[T], *Ts]','[()]','TypeError'),
775777
('generic[list[T], *Ts]','[int]','generic[list[int]]'),
776778
('generic[list[T], *Ts]','[int, str]','generic[list[int], str]'),
777779
('generic[list[T], *Ts]','[int, str, bool]','generic[list[int], str, bool]'),
778780

781+
('generic[*Ts, T]','[()]','TypeError'),
779782
('generic[*Ts, T]','[int]','generic[int]'),
780783
('generic[*Ts, T]','[int, str]','generic[int, str]'),
781784
('generic[*Ts, T]','[int, str, bool]','generic[int, str, bool]'),
785+
('generic[*Ts, list[T]]','[()]','TypeError'),
782786
('generic[*Ts, list[T]]','[int]','generic[list[int]]'),
783787
('generic[*Ts, list[T]]','[int, str]','generic[int, list[str]]'),
784788
('generic[*Ts, list[T]]','[int, str, bool]','generic[int, str, list[bool]]'),
785789

790+
('generic[T1, T2, *Ts]','[()]','TypeError'),
791+
('generic[T1, T2, *Ts]','[int]','TypeError'),
792+
('generic[T1, T2, *Ts]','[int, str]','generic[int, str]'),
793+
('generic[T1, T2, *Ts]','[int, str, bool]','generic[int, str, bool]'),
794+
('generic[T1, T2, *Ts]','[int, str, bool, bytes]','generic[int, str, bool, bytes]'),
795+
796+
('generic[*Ts, T1, T2]','[()]','TypeError'),
797+
('generic[*Ts, T1, T2]','[int]','TypeError'),
798+
('generic[*Ts, T1, T2]','[int, str]','generic[int, str]'),
799+
('generic[*Ts, T1, T2]','[int, str, bool]','generic[int, str, bool]'),
800+
('generic[*Ts, T1, T2]','[int, str, bool, bytes]','generic[int, str, bool, bytes]'),
801+
802+
('generic[T1, *Ts, T2]','[()]','TypeError'),
803+
('generic[T1, *Ts, T2]','[int]','TypeError'),
804+
('generic[T1, *Ts, T2]','[int, str]','generic[int, str]'),
805+
('generic[T1, *Ts, T2]','[int, str, bool]','generic[int, str, bool]'),
806+
('generic[T1, *Ts, T2]','[int, str, bool, bytes]','generic[int, str, bool, bytes]'),
807+
786808
('generic[T, *Ts]','[*tuple_type[int, ...]]','generic[int, *tuple_type[int, ...]]'),
787809
('generic[T, *Ts]','[str, *tuple_type[int, ...]]','generic[str, *tuple_type[int, ...]]'),
788810
('generic[T, *Ts]','[*tuple_type[int, ...], str]','generic[int, *tuple_type[int, ...], str]'),
@@ -7190,6 +7212,65 @@ class X(Generic[P, P2]):
71907212
self.assertEqual(G1.__args__, ((int,str), (bytes,)))
71917213
self.assertEqual(G2.__args__, ((int,), (str,bytes)))
71927214

7215+
deftest_typevartuple_and_paramspecs_in_user_generics(self):
7216+
Ts=TypeVarTuple("Ts")
7217+
P=ParamSpec("P")
7218+
7219+
classX(Generic[*Ts,P]):
7220+
f:Callable[P,int]
7221+
g:Tuple[*Ts]
7222+
7223+
G1=X[int, [bytes]]
7224+
self.assertEqual(G1.__args__, (int, (bytes,)))
7225+
G2=X[int,str, [bytes]]
7226+
self.assertEqual(G2.__args__, (int,str, (bytes,)))
7227+
G3=X[[bytes]]
7228+
self.assertEqual(G3.__args__, ((bytes,),))
7229+
G4=X[[]]
7230+
self.assertEqual(G4.__args__, ((),))
7231+
withself.assertRaises(TypeError):
7232+
X[()]
7233+
7234+
classY(Generic[P,*Ts]):
7235+
f:Callable[P,int]
7236+
g:Tuple[*Ts]
7237+
7238+
G1=Y[[bytes],int]
7239+
self.assertEqual(G1.__args__, ((bytes,),int))
7240+
G2=Y[[bytes],int,str]
7241+
self.assertEqual(G2.__args__, ((bytes,),int,str))
7242+
G3=Y[[bytes]]
7243+
self.assertEqual(G3.__args__, ((bytes,),))
7244+
G4=Y[[]]
7245+
self.assertEqual(G4.__args__, ((),))
7246+
withself.assertRaises(TypeError):
7247+
Y[()]
7248+
7249+
deftest_typevartuple_and_paramspecs_in_generic_aliases(self):
7250+
P=ParamSpec('P')
7251+
T=TypeVar('T')
7252+
Ts=TypeVarTuple('Ts')
7253+
7254+
forCinCallable,collections.abc.Callable:
7255+
withself.subTest(generic=C):
7256+
A=C[P,Tuple[*Ts]]
7257+
B=A[[int,str],bytes,float]
7258+
self.assertEqual(B.__args__, (int,str,Tuple[bytes,float]))
7259+
7260+
classX(Generic[T,P]):
7261+
pass
7262+
7263+
A=X[Tuple[*Ts],P]
7264+
B=A[bytes,float, [int,str]]
7265+
self.assertEqual(B.__args__, (Tuple[bytes,float], (int,str,)))
7266+
7267+
classY(Generic[P,T]):
7268+
pass
7269+
7270+
A=Y[P,Tuple[*Ts]]
7271+
B=A[[int,str],bytes,float]
7272+
self.assertEqual(B.__args__, ((int,str,),Tuple[bytes,float]))
7273+
71937274
deftest_var_substitution(self):
71947275
T=TypeVar("T")
71957276
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)
@@ -1226,7 +1207,18 @@ def __typing_subst__(self, arg):
12261207
returnarg
12271208

12281209
def__typing_prepare_subst__(self,alias,args):
1229-
return_prepare_paramspec_params(alias,args)
1210+
params=alias.__parameters__
1211+
i=params.index(self)
1212+
ifi>=len(args):
1213+
raiseTypeError(f"Too few arguments for{alias}")
1214+
# Special case where Z[[int, str, bool]] == Z[int, str, bool] in PEP 612.
1215+
iflen(params)==1andnot_is_param_expr(args[0]):
1216+
asserti==0
1217+
args= (args,)
1218+
# Convert lists to tuples to help other libraries cache the results.
1219+
elifisinstance(args[i],list):
1220+
args= (*args[:i],tuple(args[i]),*args[i+1:])
1221+
returnargs
12301222

12311223
def_is_dunder(attr):
12321224
returnattr.startswith('__')andattr.endswith('__')
@@ -1789,23 +1781,13 @@ def __class_getitem__(cls, params):
17891781
ifnotisinstance(params,tuple):
17901782
params= (params,)
17911783

1792-
ifnotparams:
1793-
# We're only ok with `params` being empty if the class's only type
1794-
# parameter is a `TypeVarTuple` (which can contain zero types).
1795-
class_params=getattr(cls,"__parameters__",None)
1796-
only_class_parameter_is_typevartuple= (
1797-
class_paramsisnotNone
1798-
andlen(class_params)==1
1799-
andisinstance(class_params[0],TypeVarTuple)
1800-
)
1801-
ifnotonly_class_parameter_is_typevartuple:
1802-
raiseTypeError(
1803-
f"Parameter list to{cls.__qualname__}[...] cannot be empty"
1804-
)
1805-
18061784
params=tuple(_type_convert(p)forpinparams)
18071785
ifclsin (Generic,Protocol):
18081786
# Generic and Protocol can only be subscripted with unique type variables.
1787+
ifnotparams:
1788+
raiseTypeError(
1789+
f"Parameter list to{cls.__qualname__}[...] cannot be empty"
1790+
)
18091791
ifnotall(_is_typevar_like(p)forpinparams):
18101792
raiseTypeError(
18111793
f"Parameters to{cls.__name__}[...] must all be type variables "
@@ -1815,13 +1797,20 @@ def __class_getitem__(cls, params):
18151797
f"Parameters to{cls.__name__}[...] must all be unique")
18161798
else:
18171799
# Subscripting a regular Generic subclass.
1818-
ifany(isinstance(t,ParamSpec)fortincls.__parameters__):
1819-
params=_prepare_paramspec_params(cls,params)
1820-
elifnotany(isinstance(p,TypeVarTuple)forpincls.__parameters__):
1821-
# We only run this if there are no TypeVarTuples, because we
1822-
# don't check variadic generic arity at runtime (to reduce
1823-
# complexity of typing.py).
1824-
_check_generic(cls,params,len(cls.__parameters__))
1800+
forparamincls.__parameters__:
1801+
prepare=getattr(param,'__typing_prepare_subst__',None)
1802+
ifprepareisnotNone:
1803+
params=prepare(cls,params)
1804+
_check_generic(cls,params,len(cls.__parameters__))
1805+
1806+
new_args= []
1807+
forparam,new_arginzip(cls.__parameters__,params):
1808+
ifisinstance(param,TypeVarTuple):
1809+
new_args.extend(new_arg)
1810+
else:
1811+
new_args.append(new_arg)
1812+
params=tuple(new_args)
1813+
18251814
return_GenericAlias(cls,params,
18261815
_paramspec_tvars=True)
18271816

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