@@ -1157,10 +1157,112 @@ def _is_unpacked_arbitrary_length_tuple(x: Any) -> bool:
1157
1157
_TypeVarOrTypeVarTuple = TypeVar | TypeVarTuple
1158
1158
1159
1159
1160
+ def _replace_degenerate_unpacked_tuples (
1161
+ args : tuple [type , ...]
1162
+ ) -> tuple [type , ...]:
1163
+ """Replaces e.g. `*tuple[int]` with just `int` in `args`."""
1164
+ new_args = []
1165
+ for arg in args :
1166
+ if (_is_unpacked_tuple (arg )
1167
+ and not _is_unpacked_arbitrary_length_tuple (arg )):
1168
+ arg_tuple = arg .__args__ [0 ] # The actual tuple[int]
1169
+ new_args .extend (arg_tuple .__args__ )
1170
+ else :
1171
+ new_args .append (arg )
1172
+ return tuple (new_args )
1173
+
1174
+
1175
+ def _determine_typevar_substition_no_typevartuples (
1176
+ typevars : tuple [TypeVar , ...],
1177
+ args : tuple [type , ...]
1178
+ ) -> dict [TypeVar , type ]:
1179
+ if any (_is_unpacked_arbitrary_length_tuple (arg ) for arg in args ):
1180
+ raise TypeError (f"Cannot assign type arguments '{ args } ' to type "
1181
+ f"variables '{ typevars } ': cannot assign "
1182
+ "unpacked arbitrary-length tuple to a TypeVar" )
1183
+ if len (typevars ) != len (args ):
1184
+ raise TypeError (f"Number of type variables ({ len (typevars )} ) "
1185
+ f"doesn't match number of type "
1186
+ f"arguments ({ len (args )} )" )
1187
+ return dict (zip (typevars , args ))
1188
+
1189
+
1190
+ def _count_num_items_before_and_after (
1191
+ items : tuple [Any , ...],
1192
+ item_of_interest : Any ,
1193
+ ) -> tuple [int , int ]:
1194
+ item_of_interest_idxs = [i for i , x in enumerate (items )
1195
+ if x == item_of_interest ]
1196
+ if not item_of_interest_idxs :
1197
+ raise ValueError ("Item of interest not found" )
1198
+ if len (item_of_interest_idxs ) > 1 :
1199
+ raise ValueError ("Item of interest occurs more than once" )
1200
+ [item_of_interest_idx ] = item_of_interest_idxs
1201
+ num_start = item_of_interest_idx
1202
+ # Assuming len(items) == 3:
1203
+ # * If item_of_interest_idx == 0, there are 2 items after item_of_interest.
1204
+ # * If item_of_interest_idx == 2, there are 0 items after item_of_interest.
1205
+ num_end = len (items ) - item_of_interest_idx - 1
1206
+ return num_start , num_end
1207
+
1208
+
1209
+ def _determine_typevar_substitution_single_typevartuple (
1210
+ typevars : tuple [_TypeVarOrTypeVarTuple , ...],
1211
+ args : tuple [type , ...]
1212
+ ) -> dict [_TypeVarOrTypeVarTuple , type | tuple [type , ...]]:
1213
+ [typevartuple_idx ] = [i for i , x in enumerate (typevars )
1214
+ if isinstance (x , TypeVarTuple )]
1215
+ typevartuple = typevars [typevartuple_idx ]
1216
+ num_start_typevars , num_end_typevars = _count_num_items_before_and_after (
1217
+ typevars , typevartuple
1218
+ )
1219
+
1220
+ # Even if one of the args is an unpacked arbitrary-length tuple, we still
1221
+ # need at least as many args as normal TypeVars.
1222
+ # Couldn't we split the arbitrary-length tuples across multiple TypeVars?
1223
+ # No, because an arbitrary-length tuple could have length zero!
1224
+ if len (args ) < num_start_typevars + num_end_typevars :
1225
+ raise TypeError (
1226
+ "Expected at least {} type parameters, but only got {}" .format (
1227
+ num_start_typevars + num_end_typevars , len (args )
1228
+ )
1229
+ )
1230
+
1231
+ if num_start_typevars == num_end_typevars == 0 :
1232
+ # It's just a single TypeVarTuple.
1233
+ return {typevars [0 ]: args }
1234
+ elif num_end_typevars == 0 :
1235
+ args_for_typevartuple = args [num_start_typevars :]
1236
+ args_for_typevars = args [:num_start_typevars ]
1237
+ if any (_is_unpacked_arbitrary_length_tuple (arg )
1238
+ for arg in args_for_typevars ):
1239
+ raise TypeError (f"Cannot assign type arguments '{ args } ' to type "
1240
+ f"variables '{ typevars } ': cannot assign "
1241
+ "arbitrary-length tuple to a TypeVar" )
1242
+ return {
1243
+ ** dict (zip (typevars [:num_start_typevars ], args_for_typevars )),
1244
+ typevartuple : args_for_typevartuple ,
1245
+ }
1246
+ else :
1247
+ args_for_left_typevars = args [:num_start_typevars ]
1248
+ args_for_typevartuple = args [num_start_typevars :- num_end_typevars ]
1249
+ args_for_right_typevars = args [- num_end_typevars :]
1250
+ if any (_is_unpacked_arbitrary_length_tuple (arg )
1251
+ for arg in args_for_left_typevars + args_for_right_typevars ):
1252
+ raise TypeError (f"Cannot assign type arguments '{ args } ' to type "
1253
+ f"variables '{ typevars } ': cannot assign "
1254
+ "arbitrary-length tuple to a TypeVar" )
1255
+ return {
1256
+ ** dict (zip (typevars [:num_start_typevars ], args_for_left_typevars )),
1257
+ typevartuple : args_for_typevartuple ,
1258
+ ** dict (zip (typevars [- num_end_typevars :], args_for_right_typevars )),
1259
+ }
1260
+
1261
+
1160
1262
def _determine_typevar_substitution (
1161
1263
typevars : tuple [_TypeVarOrTypeVarTuple , ...],
1162
1264
args : tuple [type , ...]
1163
- ) -> dict [_TypeVarOrTypeVarTuple , type ]:
1265
+ ) -> dict [_TypeVarOrTypeVarTuple , type | tuple [ type , ...] ]:
1164
1266
"""Determines how to assign type arguments to type variables.
1165
1267
1166
1268
Args:
@@ -1256,83 +1358,11 @@ def _determine_typevar_substitution(
1256
1358
raise TypeError ("At most 1 TypeVarTuple may be used in a type "
1257
1359
f"parameter list, but saw { num_typevartuples } " )
1258
1360
1259
- # First, we should go through `args` to replace e.g. *tuple[int] with int.
1260
- new_args = []
1261
- for arg in args :
1262
- if (_is_unpacked_tuple (arg )
1263
- and not _is_unpacked_arbitrary_length_tuple (arg )):
1264
- arg_tuple = arg .__args__ [0 ] # The actual tuple[int]
1265
- new_args .extend (arg_tuple .__args__ )
1266
- else :
1267
- new_args .append (arg )
1268
- args = tuple (new_args )
1269
-
1270
- # Case 1: typevars does not contain any TypeVarTuples
1361
+ args = _replace_degenerate_unpacked_tuples (args )
1271
1362
1272
1363
if num_typevartuples == 0 :
1273
- if any (_is_unpacked_arbitrary_length_tuple (arg ) for arg in args ):
1274
- raise TypeError (f"Cannot assign type arguments '{ args } ' to type "
1275
- f"variables '{ typevars } ': cannot assign "
1276
- "unpacked arbitrary-length tuple to a TypeVar" )
1277
- if len (typevars ) != len (args ):
1278
- raise TypeError (f"Number of type variables ({ len (typevars )} ) "
1279
- f"doesn't match number of type "
1280
- f"arguments ({ len (args )} )" )
1281
- return dict (zip (typevars , args ))
1282
-
1283
- # Case 2: typevars contains a single TypeVarTuple
1284
-
1285
- [typevartuple_idx ] = [i for i , x in enumerate (typevars )
1286
- if isinstance (x , TypeVarTuple )]
1287
- typevartuple = typevars [typevartuple_idx ]
1288
- num_start_typevars = typevartuple_idx
1289
- # Assuming len(typevars) == 3:
1290
- # * If typevartuple_idx == 0, there are 2 TypeVars at
1291
- # the end of typevars.
1292
- # * If typevartuple_idx == 2 there are 0 TypeVars at
1293
- # the end of typevars.
1294
- num_end_typevars = len (typevars ) - typevartuple_idx - 1
1295
-
1296
- # Even if one of the args is an unpacked arbitrary-length tuple, we still
1297
- # need at least as many args as normal TypeVars.
1298
- # Couldn't we split the arbitrary-length tuples across multiple TypeVars?
1299
- # No, because an arbitrary-length tuple could have length zero!
1300
- if len (args ) < num_start_typevars + num_end_typevars :
1301
- raise TypeError (
1302
- "Expected at least {} type parameters, but only got {}" .format (
1303
- num_start_typevars + num_end_typevars , len (args )
1304
- )
1305
- )
1306
-
1307
- if num_start_typevars == num_end_typevars == 0 :
1308
- # It's just a single TypeVarTuple.
1309
- return {typevars [0 ]: args }
1310
- elif num_end_typevars == 0 :
1311
- args_for_typevartuple = args [num_start_typevars :]
1312
- args_for_typevars = args [:num_start_typevars ]
1313
- if any (_is_unpacked_arbitrary_length_tuple (arg )
1314
- for arg in args_for_typevars ):
1315
- raise TypeError (f"Cannot assign type arguments '{ args } ' to type "
1316
- f"variables '{ typevars } ': cannot assign "
1317
- "arbitrary-length tuple to a TypeVar" )
1318
- return {
1319
- ** dict (zip (typevars [:num_start_typevars ], args_for_typevars )),
1320
- typevartuple : args_for_typevartuple ,
1321
- }
1322
- else :
1323
- args_for_left_typevars = args [:num_start_typevars ]
1324
- args_for_typevartuple = args [num_start_typevars :- num_end_typevars ]
1325
- args_for_right_typevars = args [- num_end_typevars :]
1326
- if any (_is_unpacked_arbitrary_length_tuple (arg )
1327
- for arg in args_for_left_typevars + args_for_right_typevars ):
1328
- raise TypeError (f"Cannot assign type arguments '{ args } ' to type "
1329
- f"variables '{ typevars } ': cannot assign "
1330
- "arbitrary-length tuple to a TypeVar" )
1331
- return {
1332
- ** dict (zip (typevars [:num_start_typevars ], args_for_left_typevars )),
1333
- typevartuple : args_for_typevartuple ,
1334
- ** dict (zip (typevars [- num_end_typevars :], args_for_right_typevars )),
1335
- }
1364
+ return _determine_typevar_substition_no_typevartuples (typevars , args )
1365
+ return _determine_typevar_substitution_single_typevartuple (typevars , args )
1336
1366
1337
1367
1338
1368
# Special typing constructs Union, Optional, Generic, Callable and Tuple
0 commit comments