@ -195,15 +195,17 @@ def _type_repr(obj):
return repr ( obj )
def _collect_type_vars ( types ) :
""" Collect all type variable-like variables contained
def _collect_type_vars ( types , typevar_types = None ) :
""" Collect all type variable contained
in types in order of first appearance ( lexicographic order ) . For example : :
_collect_type_vars ( ( T , List [ S , T ] ) ) == ( T , S )
"""
if typevar_types is None :
typevar_types = TypeVar
tvars = [ ]
for t in types :
if isinstance ( t , _TypeVarLike ) and t not in tvars :
if isinstance ( t , typevar_types ) and t not in tvars :
tvars . append ( t )
if isinstance ( t , ( _GenericAlias , GenericAlias ) ) :
tvars . extend ( [ t for t in t . __parameters__ if t not in tvars ] )
@ -932,7 +934,8 @@ class _BaseGenericAlias(_Final, _root=True):
raise AttributeError ( attr )
def __setattr__ ( self , attr , val ) :
if _is_dunder ( attr ) or attr in ( ' _name ' , ' _inst ' , ' _nparams ' ) :
if _is_dunder ( attr ) or attr in { ' _name ' , ' _inst ' , ' _nparams ' ,
' _typevar_types ' , ' _paramspec_tvars ' } :
super ( ) . __setattr__ ( attr , val )
else :
setattr ( self . __origin__ , attr , val )
@ -957,14 +960,18 @@ class _BaseGenericAlias(_Final, _root=True):
class _GenericAlias ( _BaseGenericAlias , _root = True ) :
def __init__ ( self , origin , params , * , inst = True , name = None ) :
def __init__ ( self , origin , params , * , inst = True , name = None ,
_typevar_types = TypeVar ,
_paramspec_tvars = False ) :
super ( ) . __init__ ( origin , inst = inst , name = name )
if not isinstance ( params , tuple ) :
params = ( params , )
self . __args__ = tuple ( . . . if a is _TypingEllipsis else
( ) if a is _TypingEmpty else
a for a in params )
self . __parameters__ = _collect_type_vars ( params )
self . __parameters__ = _collect_type_vars ( params , typevar_types = _typevar_types )
self . _typevar_types = _typevar_types
self . _paramspec_tvars = _paramspec_tvars
if not name :
self . __module__ = origin . __module__
@ -991,14 +998,15 @@ class _GenericAlias(_BaseGenericAlias, _root=True):
if not isinstance ( params , tuple ) :
params = ( params , )
params = tuple ( _type_convert ( p ) for p in params )
if any ( isinstance ( t , ParamSpec ) for t in self . __parameters__ ) :
params = _prepare_paramspec_params ( self , params )
if self . _paramspec_tvars :
if any ( isinstance ( t , ParamSpec ) for t in self . __parameters__ ) :
params = _prepare_paramspec_params ( self , params )
_check_generic ( self , params , len ( self . __parameters__ ) )
subst = dict ( zip ( self . __parameters__ , params ) )
new_args = [ ]
for arg in self . __args__ :
if isinstance ( arg , _TypeVarLike ) :
if isinstance ( arg , self . _typevar_types ) :
arg = subst [ arg ]
elif isinstance ( arg , ( _GenericAlias , GenericAlias ) ) :
subparams = arg . __parameters__
@ -1115,7 +1123,9 @@ class _CallableGenericAlias(_GenericAlias, _root=True):
class _CallableType ( _SpecialGenericAlias , _root = True ) :
def copy_with ( self , params ) :
return _CallableGenericAlias ( self . __origin__ , params ,
name = self . _name , inst = self . _inst )
name = self . _name , inst = self . _inst ,
_typevar_types = ( TypeVar , ParamSpec ) ,
_paramspec_tvars = True )
def __getitem__ ( self , params ) :
if not isinstance ( params , tuple ) or len ( params ) != 2 :
@ -1208,7 +1218,10 @@ class _LiteralGenericAlias(_GenericAlias, _root=True):
class _ConcatenateGenericAlias ( _GenericAlias , _root = True ) :
pass
def __init__ ( self , * args , * * kwargs ) :
super ( ) . __init__ ( * args , * * kwargs ,
_typevar_types = ( TypeVar , ParamSpec ) ,
_paramspec_tvars = True )
class Generic :
@ -1244,7 +1257,7 @@ class Generic:
params = tuple ( _type_convert ( p ) for p in params )
if cls in ( Generic , Protocol ) :
# Generic and Protocol can only be subscripted with unique type variables.
if not all ( isinstance ( p , _TypeVarLike ) for p in params ) :
if not all ( isinstance ( p , ( TypeVar , ParamSpec ) ) for p in params ) :
raise TypeError (
f " Parameters to {cls.__name__}[...] must all be type variables "
f " or parameter specification variables. " )
@ -1256,7 +1269,9 @@ class Generic:
if any ( isinstance ( t , ParamSpec ) for t in cls . __parameters__ ) :
params = _prepare_paramspec_params ( cls , params )
_check_generic ( cls , params , len ( cls . __parameters__ ) )
return _GenericAlias ( cls , params )
return _GenericAlias ( cls , params ,
_typevar_types = ( TypeVar , ParamSpec ) ,
_paramspec_tvars = True )
def __init_subclass__ ( cls , * args , * * kwargs ) :
super ( ) . __init_subclass__ ( * args , * * kwargs )
@ -1268,7 +1283,7 @@ class Generic:
if error :
raise TypeError ( " Cannot inherit from plain Generic " )
if ' __orig_bases__ ' in cls . __dict__ :
tvars = _collect_type_vars ( cls . __orig_bases__ )
tvars = _collect_type_vars ( cls . __orig_bases__ , ( TypeVar , ParamSpec ) )
# Look for Generic[T1, ..., Tn].
# If found, tvars must be a subset of it.
# If not found, tvars is it.