@@ -1000,16 +1000,41 @@ def __dir__(self):
1000
1000
1001
1001
1002
1002
class _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 ,
1004
1029
_typevar_types = TypeVar ,
1005
1030
_paramspec_tvars = False ):
1006
1031
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 ,)
1009
1034
self .__args__ = tuple (... if a is _TypingEllipsis else
1010
1035
() 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 )
1013
1038
self ._typevar_types = _typevar_types
1014
1039
self ._paramspec_tvars = _paramspec_tvars
1015
1040
if not name :
@@ -1031,44 +1056,97 @@ def __ror__(self, left):
1031
1056
return Union [left , self ]
1032
1057
1033
1058
@_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
+
1035
1075
if self .__origin__ in (Generic , Protocol ):
1036
1076
# Can't subscript Generic[...] or Protocol[...].
1037
1077
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 )
1041
1083
if (self ._paramspec_tvars
1042
1084
and any (isinstance (t , ParamSpec ) for t in self .__parameters__ )):
1043
- params = _prepare_paramspec_params (self , params )
1085
+ args = _prepare_paramspec_params (self , args )
1044
1086
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 ))
1046
1110
1047
- subst = dict (zip (self .__parameters__ , params ))
1048
1111
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
1056
1125
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 )
1066
1143
else :
1067
- new_args .append (arg )
1068
- return self .copy_with (tuple (new_args ))
1144
+ new_args .append (new_arg )
1069
1145
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 )
1072
1150
1073
1151
def __repr__ (self ):
1074
1152
if self ._name :
0 commit comments