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

[3.11] gh-99344, gh-99379, gh-99382: Fix issues in substitution of ParamSpec and TypeVarTuple (GH-99412)#99866

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletionsLib/test/test_typing.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -769,20 +769,42 @@ class C(Generic[*Ts]): pass
('generic[*Ts]','[*Ts]','generic[*Ts]'),
('generic[*Ts]','[T, *Ts]','generic[T, *Ts]'),
('generic[*Ts]','[*Ts, T]','generic[*Ts, T]'),
('generic[T, *Ts]','[()]','TypeError'),
('generic[T, *Ts]','[int]','generic[int]'),
('generic[T, *Ts]','[int, str]','generic[int, str]'),
('generic[T, *Ts]','[int, str, bool]','generic[int, str, bool]'),
('generic[list[T], *Ts]','[()]','TypeError'),
('generic[list[T], *Ts]','[int]','generic[list[int]]'),
('generic[list[T], *Ts]','[int, str]','generic[list[int], str]'),
('generic[list[T], *Ts]','[int, str, bool]','generic[list[int], str, bool]'),

('generic[*Ts, T]','[()]','TypeError'),
('generic[*Ts, T]','[int]','generic[int]'),
('generic[*Ts, T]','[int, str]','generic[int, str]'),
('generic[*Ts, T]','[int, str, bool]','generic[int, str, bool]'),
('generic[*Ts, list[T]]','[()]','TypeError'),
('generic[*Ts, list[T]]','[int]','generic[list[int]]'),
('generic[*Ts, list[T]]','[int, str]','generic[int, list[str]]'),
('generic[*Ts, list[T]]','[int, str, bool]','generic[int, str, list[bool]]'),

('generic[T1, T2, *Ts]','[()]','TypeError'),
('generic[T1, T2, *Ts]','[int]','TypeError'),
('generic[T1, T2, *Ts]','[int, str]','generic[int, str]'),
('generic[T1, T2, *Ts]','[int, str, bool]','generic[int, str, bool]'),
('generic[T1, T2, *Ts]','[int, str, bool, bytes]','generic[int, str, bool, bytes]'),

('generic[*Ts, T1, T2]','[()]','TypeError'),
('generic[*Ts, T1, T2]','[int]','TypeError'),
('generic[*Ts, T1, T2]','[int, str]','generic[int, str]'),
('generic[*Ts, T1, T2]','[int, str, bool]','generic[int, str, bool]'),
('generic[*Ts, T1, T2]','[int, str, bool, bytes]','generic[int, str, bool, bytes]'),

('generic[T1, *Ts, T2]','[()]','TypeError'),
('generic[T1, *Ts, T2]','[int]','TypeError'),
('generic[T1, *Ts, T2]','[int, str]','generic[int, str]'),
('generic[T1, *Ts, T2]','[int, str, bool]','generic[int, str, bool]'),
('generic[T1, *Ts, T2]','[int, str, bool, bytes]','generic[int, str, bool, bytes]'),

('generic[T, *Ts]','[*tuple_type[int, ...]]','generic[int, *tuple_type[int, ...]]'),
('generic[T, *Ts]','[str, *tuple_type[int, ...]]','generic[str, *tuple_type[int, ...]]'),
('generic[T, *Ts]','[*tuple_type[int, ...], str]','generic[int, *tuple_type[int, ...], str]'),
Expand DownExpand Up@@ -7190,6 +7212,65 @@ class X(Generic[P, P2]):
self.assertEqual(G1.__args__, ((int,str), (bytes,)))
self.assertEqual(G2.__args__, ((int,), (str,bytes)))

deftest_typevartuple_and_paramspecs_in_user_generics(self):
Ts=TypeVarTuple("Ts")
P=ParamSpec("P")

classX(Generic[*Ts,P]):
f:Callable[P,int]
g:Tuple[*Ts]

G1=X[int, [bytes]]
self.assertEqual(G1.__args__, (int, (bytes,)))
G2=X[int,str, [bytes]]
self.assertEqual(G2.__args__, (int,str, (bytes,)))
G3=X[[bytes]]
self.assertEqual(G3.__args__, ((bytes,),))
G4=X[[]]
self.assertEqual(G4.__args__, ((),))
withself.assertRaises(TypeError):
X[()]

classY(Generic[P,*Ts]):
f:Callable[P,int]
g:Tuple[*Ts]

G1=Y[[bytes],int]
self.assertEqual(G1.__args__, ((bytes,),int))
G2=Y[[bytes],int,str]
self.assertEqual(G2.__args__, ((bytes,),int,str))
G3=Y[[bytes]]
self.assertEqual(G3.__args__, ((bytes,),))
G4=Y[[]]
self.assertEqual(G4.__args__, ((),))
withself.assertRaises(TypeError):
Y[()]

deftest_typevartuple_and_paramspecs_in_generic_aliases(self):
P=ParamSpec('P')
T=TypeVar('T')
Ts=TypeVarTuple('Ts')

forCinCallable,collections.abc.Callable:
withself.subTest(generic=C):
A=C[P,Tuple[*Ts]]
B=A[[int,str],bytes,float]
self.assertEqual(B.__args__, (int,str,Tuple[bytes,float]))

classX(Generic[T,P]):
pass

A=X[Tuple[*Ts],P]
B=A[bytes,float, [int,str]]
self.assertEqual(B.__args__, (Tuple[bytes,float], (int,str,)))

classY(Generic[P,T]):
pass

A=Y[P,Tuple[*Ts]]
B=A[[int,str],bytes,float]
self.assertEqual(B.__args__, ((int,str,),Tuple[bytes,float]))

deftest_var_substitution(self):
T=TypeVar("T")
P=ParamSpec("P")
Expand Down
71 changes: 30 additions & 41 deletionsLib/typing.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -284,25 +284,6 @@ def _unpack_args(args):
newargs.append(arg)
returnnewargs

def_prepare_paramspec_params(cls,params):
"""Prepares the parameters for a Generic containing ParamSpec
variables (internal helper).
"""
# Special case where Z[[int, str, bool]] == Z[int, str, bool] in PEP 612.
if (len(cls.__parameters__)==1
andparamsandnot_is_param_expr(params[0])):
assertisinstance(cls.__parameters__[0],ParamSpec)
return (params,)
else:
_check_generic(cls,params,len(cls.__parameters__))
_params= []
# Convert lists to tuples to help other libraries cache the results.
forp,tvarinzip(params,cls.__parameters__):
ifisinstance(tvar,ParamSpec)andisinstance(p,list):
p=tuple(p)
_params.append(p)
returntuple(_params)

def_deduplicate(params):
# Weed out strict duplicates, preserving the first of each occurrence.
all_params=set(params)
Expand DownExpand Up@@ -1226,7 +1207,18 @@ def __typing_subst__(self, arg):
returnarg

def__typing_prepare_subst__(self,alias,args):
return_prepare_paramspec_params(alias,args)
params=alias.__parameters__
i=params.index(self)
ifi>=len(args):
raiseTypeError(f"Too few arguments for{alias}")
# Special case where Z[[int, str, bool]] == Z[int, str, bool] in PEP 612.
iflen(params)==1andnot_is_param_expr(args[0]):
asserti==0
args= (args,)
# Convert lists to tuples to help other libraries cache the results.
elifisinstance(args[i],list):
args= (*args[:i],tuple(args[i]),*args[i+1:])
returnargs

def_is_dunder(attr):
returnattr.startswith('__')andattr.endswith('__')
Expand DownExpand Up@@ -1789,23 +1781,13 @@ def __class_getitem__(cls, params):
ifnotisinstance(params,tuple):
params= (params,)

ifnotparams:
# We're only ok with `params` being empty if the class's only type
# parameter is a `TypeVarTuple` (which can contain zero types).
class_params=getattr(cls,"__parameters__",None)
only_class_parameter_is_typevartuple= (
class_paramsisnotNone
andlen(class_params)==1
andisinstance(class_params[0],TypeVarTuple)
)
ifnotonly_class_parameter_is_typevartuple:
raiseTypeError(
f"Parameter list to{cls.__qualname__}[...] cannot be empty"
)

params=tuple(_type_convert(p)forpinparams)
ifclsin (Generic,Protocol):
# Generic and Protocol can only be subscripted with unique type variables.
ifnotparams:
raiseTypeError(
f"Parameter list to{cls.__qualname__}[...] cannot be empty"
)
ifnotall(_is_typevar_like(p)forpinparams):
raiseTypeError(
f"Parameters to{cls.__name__}[...] must all be type variables "
Expand All@@ -1815,13 +1797,20 @@ def __class_getitem__(cls, params):
f"Parameters to{cls.__name__}[...] must all be unique")
else:
# Subscripting a regular Generic subclass.
ifany(isinstance(t,ParamSpec)fortincls.__parameters__):
params=_prepare_paramspec_params(cls,params)
elifnotany(isinstance(p,TypeVarTuple)forpincls.__parameters__):
# We only run this if there are no TypeVarTuples, because we
# don't check variadic generic arity at runtime (to reduce
# complexity of typing.py).
_check_generic(cls,params,len(cls.__parameters__))
forparamincls.__parameters__:
prepare=getattr(param,'__typing_prepare_subst__',None)
ifprepareisnotNone:
params=prepare(cls,params)
_check_generic(cls,params,len(cls.__parameters__))

new_args= []
forparam,new_arginzip(cls.__parameters__,params):
ifisinstance(param,TypeVarTuple):
new_args.extend(new_arg)
else:
new_args.append(new_arg)
params=tuple(new_args)

return_GenericAlias(cls,params,
_paramspec_tvars=True)

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

[8]ページ先頭

©2009-2025 Movatter.jp