@@ -1000,16 +1000,41 @@ def __dir__(self):
10001000
10011001
10021002class _GenericAlias (_BaseGenericAlias , _root = True ):
1003- def __init__ (self , origin , params , * , inst = True , name = None ,
1003+ # The type of parameterized generics.
1004+ #
1005+ # That is, for example, `type(List[int])` is `_GenericAlias`.
1006+ #
1007+ # Objects which are instances of this class include:
1008+ # * Parameterized container types, e.g. `Tuple[int]`, `List[int]`.
1009+ # * Note that native container types, e.g. `tuple`, `list`, use
1010+ # `types.GenericAlias` instead.
1011+ # * Parameterized classes:
1012+ # T = TypeVar('T')
1013+ # class C(Generic[T]): pass
1014+ # # C[int] is a _GenericAlias
1015+ # * `Callable` aliases, generic `Callable` aliases, and
1016+ # parameterized `Callable` aliases:
1017+ # T = TypeVar('T')
1018+ # # _CallableGenericAlias inherits from _GenericAlias.
1019+ # A = Callable[[], None] # _CallableGenericAlias
1020+ # B = Callable[[T], None] # _CallableGenericAlias
1021+ # C = B[int] # _CallableGenericAlias
1022+ # * Parameterized `Final`, `ClassVar` and `TypeGuard`:
1023+ # # All _GenericAlias
1024+ # Final[int]
1025+ # ClassVar[float]
1026+ # TypeVar[bool]
1027+
1028+ def __init__ (self , origin , args , * , inst = True , name = None ,
10041029 _typevar_types = TypeVar ,
10051030 _paramspec_tvars = False ):
10061031 super ().__init__ (origin , inst = inst , name = name )
1007- if not isinstance (params , tuple ):
1008- params = (params ,)
1032+ if not isinstance (args , tuple ):
1033+ args = (args ,)
10091034 self .__args__ = tuple (... if a is _TypingEllipsis else
10101035 () if a is _TypingEmpty else
1011- a for a in params )
1012- self .__parameters__ = _collect_type_vars (params , typevar_types = _typevar_types )
1036+ a for a in args )
1037+ self .__parameters__ = _collect_type_vars (args , typevar_types = _typevar_types )
10131038 self ._typevar_types = _typevar_types
10141039 self ._paramspec_tvars = _paramspec_tvars
10151040 if not name :
@@ -1031,44 +1056,97 @@ def __ror__(self, left):
10311056 return Union [left , self ]
10321057
10331058 @_tp_cache
1034- def __getitem__ (self , params ):
1059+ def __getitem__ (self , args ):
1060+ # Parameterizes an already-parameterized object.
1061+ #
1062+ # For example, we arrive here doing something like:
1063+ # T1 = TypeVar('T1')
1064+ # T2 = TypeVar('T2')
1065+ # T3 = TypeVar('T3')
1066+ # class A(Generic[T1]): pass
1067+ # B = A[T2] # B is a _GenericAlias
1068+ # C = B[T3] # Invokes _GenericAlias.__getitem__
1069+ #
1070+ # We also arrive here when parameterizing a generic `Callable` alias:
1071+ # T = TypeVar('T')
1072+ # C = Callable[[T], None]
1073+ # C[int] # Invokes _GenericAlias.__getitem__
1074+
10351075 if self .__origin__ in (Generic , Protocol ):
10361076 # Can't subscript Generic[...] or Protocol[...].
10371077 raise TypeError (f"Cannot subscript already-subscripted { self } " )
1038- if not isinstance (params , tuple ):
1039- params = (params ,)
1040- params = tuple (_type_convert (p ) for p in params )
1078+
1079+ # Preprocess `args`.
1080+ if not isinstance (args , tuple ):
1081+ args = (args ,)
1082+ args = tuple (_type_convert (p ) for p in args )
10411083 if (self ._paramspec_tvars
10421084 and any (isinstance (t , ParamSpec ) for t in self .__parameters__ )):
1043- params = _prepare_paramspec_params (self , params )
1085+ args = _prepare_paramspec_params (self , args )
10441086 else :
1045- _check_generic (self , params , len (self .__parameters__ ))
1087+ _check_generic (self , args , len (self .__parameters__ ))
1088+
1089+ new_args = self ._determine_new_args (args )
1090+ r = self .copy_with (new_args )
1091+ return r
1092+
1093+ def _determine_new_args (self , args ):
1094+ # Determines new __args__ for __getitem__.
1095+ #
1096+ # For example, suppose we had:
1097+ # T1 = TypeVar('T1')
1098+ # T2 = TypeVar('T2')
1099+ # class A(Generic[T1, T2]): pass
1100+ # T3 = TypeVar('T3')
1101+ # B = A[int, T3]
1102+ # C = B[str]
1103+ # `B.__args__` is `(int, T3)`, so `C.__args__` should be `(int, str)`.
1104+ # Unfortunately, this is harder than it looks, because if `T3` is
1105+ # anything more exotic than a plain `TypeVar`, we need to consider
1106+ # edge cases.
1107+
1108+ # In the example above, this would be {T3: str}
1109+ new_arg_by_param = dict (zip (self .__parameters__ , args ))
10461110
1047- subst = dict (zip (self .__parameters__ , params ))
10481111 new_args = []
1049- for arg in self .__args__ :
1050- if isinstance (arg , self ._typevar_types ):
1051- if isinstance (arg , ParamSpec ):
1052- arg = subst [arg ]
1053- if not _is_param_expr (arg ):
1054- raise TypeError (f"Expected a list of types, an ellipsis, "
1055- f"ParamSpec, or Concatenate. Got { arg } " )
1112+ for old_arg in self .__args__ :
1113+
1114+ if isinstance (old_arg , ParamSpec ):
1115+ new_arg = new_arg_by_param [old_arg ]
1116+ if not _is_param_expr (new_arg ):
1117+ raise TypeError (f"Expected a list of types, an ellipsis, "
1118+ f"ParamSpec, or Concatenate. Got { new_arg } " )
1119+ elif isinstance (old_arg , self ._typevar_types ):
1120+ new_arg = new_arg_by_param [old_arg ]
1121+ elif isinstance (old_arg , (_GenericAlias , GenericAlias , types .UnionType )):
1122+ subparams = old_arg .__parameters__
1123+ if not subparams :
1124+ new_arg = old_arg
10561125 else :
1057- arg = subst [arg ]
1058- elif isinstance (arg , (_GenericAlias , GenericAlias , types .UnionType )):
1059- subparams = arg .__parameters__
1060- if subparams :
1061- subargs = tuple (subst [x ] for x in subparams )
1062- arg = arg [subargs ]
1063- # Required to flatten out the args for CallableGenericAlias
1064- if self .__origin__ == collections .abc .Callable and isinstance (arg , tuple ):
1065- new_args .extend (arg )
1126+ subargs = tuple (new_arg_by_param [x ] for x in subparams )
1127+ new_arg = old_arg [subargs ]
1128+ else :
1129+ new_arg = old_arg
1130+
1131+ if self .__origin__ == collections .abc .Callable and isinstance (new_arg , tuple ):
1132+ # Consider the following `Callable`.
1133+ # C = Callable[[int], str]
1134+ # Here, `C.__args__` should be (int, str) - NOT ([int], str).
1135+ # That means that if we had something like...
1136+ # P = ParamSpec('P')
1137+ # T = TypeVar('T')
1138+ # C = Callable[P, T]
1139+ # D = C[[int, str], float]
1140+ # ...we need to be careful; `new_args` should end up as
1141+ # `(int, str, float)` rather than `([int, str], float)`.
1142+ new_args .extend (new_arg )
10661143 else :
1067- new_args .append (arg )
1068- return self .copy_with (tuple (new_args ))
1144+ new_args .append (new_arg )
10691145
1070- def copy_with (self , params ):
1071- return self .__class__ (self .__origin__ , params , name = self ._name , inst = self ._inst )
1146+ return tuple (new_args )
1147+
1148+ def copy_with (self , args ):
1149+ return self .__class__ (self .__origin__ , args , name = self ._name , inst = self ._inst )
10721150
10731151 def __repr__ (self ):
10741152 if self ._name :
0 commit comments