10000
We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
1 parent 40ba6ca commit a7efb91Copy full SHA for a7efb91
Include/internal/pycore_global_strings.h
@@ -202,6 +202,7 @@ struct _Py_global_strings {
202
STRUCT_FOR_ID(__truediv__)
203
STRUCT_FOR_ID(__trunc__)
204
STRUCT_FOR_ID(__typing_is_unpacked_typevartuple__)
205
+ STRUCT_FOR_ID(__typing_prepare_subst__)
206
STRUCT_FOR_ID(__typing_subst__)
207
STRUCT_FOR_ID(__typing_unpacked_tuple_args__)
208
STRUCT_FOR_ID(__warningregistry__)
Include/internal/pycore_runtime_init.h
@@ -824,6 +824,7 @@ extern "C" {
824
INIT_ID(__truediv__), \
825
INIT_ID(__trunc__), \
826
INIT_ID(__typing_is_unpacked_typevartuple__), \
827
+ INIT_ID(__typing_prepare_subst__), \
828
INIT_ID(__typing_subst__), \
829
INIT_ID(__typing_unpacked_tuple_args__), \
830
INIT_ID(__warningregistry__), \
Lib/typing.py
@@ -1065,6 +1065,42 @@ def __repr__(self):
1065
def __typing_subst__(self, arg):
1066
raise TypeError("Substitution of bare TypeVarTuple is not supported")
1067
1068
+ def __typing_prepare_subst__(self, alias, args):
1069
+ params = alias.__parameters__
1070
+ typevartuple_index = params.index(self)
1071
+ for param in enumerate(params[typevartuple_index + 1:]):
1072
+ if isinstance(param, TypeVarTuple):
1073
+ raise TypeError(f"More than one TypeVarTuple parameter in {alias}")
1074
+
1075
+ alen = len(args)
1076
+ plen = len(params)
1077
+ left = typevartuple_index
1078
+ right = plen - typevartuple_index - 1
1079
+ var_tuple_index = None
1080
+ fillarg = None
1081
+ for k, arg in enumerate(args):
1082
+ if not (isinstance(arg, type) and not isinstance(arg, GenericAlias)):
1083
+ subargs = getattr(arg, '__typing_unpacked_tuple_args__', None)
1084
+ if subargs and len(subargs) == 2 and subargs[-1] is ...:
1085
+ if var_tuple_index is not None:
1086
+ raise TypeError("More than one unpacked arbitrary-length tuple argument")
1087
+ var_tuple_index = k
1088
+ fillarg = subargs[0]
1089
1090
+ left = min(left, var_tuple_index)
1091
+ right = min(right, alen - var_tuple_index - 1)
1092
+ elif left + right > alen:
1093
+ raise TypeError(f"Too few arguments for {alias};"
1094
+ f" actual {alen}, expected at least {plen-1}")
1095
1096
+ return (
1097
+ *args[:left],
1098
+ *([fillarg]*(typevartuple_index - left)),
1099
+ tuple(args[left: alen - right]),
1100
+ *([fillarg]*(plen - right - left - typevartuple_index - 1)),
1101
+ *args[alen - right:],
1102
+ )
1103
1104
1105
class ParamSpecArgs(_Final, _Immutable, _root=True):
1106
"""The args for a ParamSpec object.
@@ -1184,6 +1220,8 @@ def __typing_subst__(self, arg):
1184
1220
f"ParamSpec, or Concatenate. Got {arg}")
1185
1221
return arg
1186
1222
1223
1224
+ return _prepare_paramspec_params(alias, args)
1187
1225
1188
1226
def _is_dunder(attr):
1189
1227
return attr.startswith('__') and attr.endswith('__')
@@ -1347,10 +1385,6 @@ def __getitem__(self, args):
1347
1385
args = (args,)
1348
1386
args = tuple(_type_convert(p) for p in args)
1349
1387
args = _unpack_args(args)
1350
- if (self._paramspec_tvars
1351
- and any(isinstance(t, ParamSpec) for t in self.__parameters__)):
1352
- args = _prepare_paramspec_params(self, args)
1353
-
1354
1388
new_args = self._determine_new_args(args)
1355
1389
r = self.copy_with(new_args)
1356
1390
return r
@@ -1372,47 +1406,16 @@ def _determine_new_args(self, args):
1372
1406
1373
1407
params = self.__parameters__
1374
1408
# In the example above, this would be {T3: str}
1375
- new_arg_by_param = {}
1376
- typevartuple_index = None
1377
- for i, param in enumerate(params):
1378
- if isinstance(param, TypeVarTuple):
1379
- if typevartuple_index is not None:
1380
- raise TypeError(f"More than one TypeVarTuple parameter in {self}")
1381
- typevartuple_index = i
1382
1409
+ for param in params:
1410
+ prepare = getattr(param, '__typing_prepare_subst__', None)
1411
+ if prepare is not None:
1412
+ args = prepare(self, args)
1383
1413
alen = len(args)
1384
1414
plen = len(params)
- left = typevartuple_index
- right = plen - typevartuple_index - 1
- var_tuple_index = None
- for k, arg in enumerate(args):
- if not (isinstance(arg, type) and not isinstance(arg, GenericAlias)):
1391
- subargs = getattr(arg, '__typing_unpacked_tuple_args__', None)
1392
- if subargs and len(subargs) == 2 and subargs[-1] is ...:
1393
- if var_tuple_index is not None:
1394
- raise TypeError("More than one unpacked arbitrary-length tuple argument")
1395
- var_tuple_index = k
1396
- fillarg = subargs[0]
1397
1398
- left = min(left, var_tuple_index)
1399
- right = min(right, alen - var_tuple_index - 1)
1400
- elif left + right > alen:
1401
- raise TypeError(f"Too few arguments for {self};"
1402
- f" actual {alen}, expected at least {plen-1}")
1403
1404
- new_arg_by_param.update(zip(params[:left], args[:left]))
1405
- for k in range(left, typevartuple_index):
- new_arg_by_param[params[k]] = fillarg
- new_arg_by_param[params[typevartuple_index]] = tuple(args[left: alen - right])
- for k in range(typevartuple_index + 1, plen - right):
- new_arg_by_param.update(zip(params[plen - right:], args[alen - right:]))
- else:
- if alen != plen:
- raise TypeError(f"Too {'many' if alen > plen else 'few'} arguments for {self};"
- f" actual {alen}, expected {plen}")
1415
- new_arg_by_param.update(zip(params, args))
+ if alen != plen:
1416
+ raise TypeError(f"Too {'many' if alen > plen else 'few'} arguments for {self};"
1417
+ f" actual {alen}, expected {plen}")
1418
+ new_arg_by_param = dict(zip(params, args))
1419
1420
new_args = []
1421
for old_arg in self.__args__:
Objects/genericaliasobject.c
@@ -269,9 +269,7 @@ _Py_make_parameters(PyObject *args)
269
a non-empty tuple, return a new reference to obj. */
270
static PyObject *
271
subs_tvars(PyObject *obj, PyObject *params,
272
- PyObject **argitems, Py_ssize_t nargs,
273
- Py_ssize_t varparam, Py_ssize_t left, Py_ssize_t right,
274
- PyObject *fillarg)
+ PyObject **argitems, Py_ssize_t nargs)
275
{
276
PyObject *subparams;
277
if (_PyObject_LookupAttr(obj, &_Py_ID(__parameters__), &subparams) < 0) {
@@ -289,30 +287,22 @@ subs_tvars(PyObject *obj, PyObject *params,
289
287
for (Py_ssize_t i = 0; i < nsubargs; ++i) {
290
288
PyObject *arg = PyTuple_GET_ITEM(subparams, i);
291
Py_ssize_t iparam = tuple_index(params, nparams, arg);
292
- if (iparam == varparam) {
293
- j = tuple_extend(&subargs, j,
294
- argitems + left, nargs - left - right);
295
- if (j < 0) {
296
- return NULL;
297
- }
298
299
- else {
300
- if (iparam >= 0) {
301
- if (iparam < left) {
302
- arg = argitems[iparam];
303
304
- else if (iparam >= nparams - right) {
305
- iparam += nargs - nparams;
306
307
308
309
- arg = fillarg;
+ if (iparam >= 0) {
+ PyObject *param = PyTuple_GET_ITEM(params, iparam);
+ arg = argitems[iparam];
+ if (Py_TYPE(param)->tp_iter && PyTuple_Check(arg)) { // TypeVarTuple
+ j = tuple_extend(&subargs, j,
+ &PyTuple_GET_ITEM(arg, 0),
+ PyTuple_GET_SIZE(arg));
+ if (j < 0) {
+ return NULL;
310
}
+ continue;
311
312
- Py_INCREF(arg);
313
- PyTuple_SET_ITEM(subargs, j, arg);
314
- j++;
315
+ Py_INCREF(arg);
+ PyTuple_SET_ITEM(subargs, j, arg);
+ j++;
316
317
assert(j == PyTuple_GET_SIZE(subargs));
318
@@ -409,27 +399,6 @@ _unpack_args(PyObject *item)
409
399
return newargs;
410
400
411
401
412
-static PyObject *
413
-_get_unpacked_var_tuple_arg(PyObject *arg)
414
-{
415
- if (PyType_Check(arg)) {
416
417
418
- PyObject *subargs = _unpacked_tuple_args(arg);
419
- if (subargs != NULL &&
420
- PyTuple_Check(subargs) &&
421
- PyTuple_GET_SIZE(subargs) == 2 &&
422
- PyTuple_GET_ITEM(subargs, 1) == Py_Ellipsis)
423
- {
424
- PyObject *subarg = PyTuple_GET_ITEM(subargs, 0);
425
- Py_INCREF(subarg);
426
- Py_DECREF(subargs);
427
- return subarg;
428
429
- Py_XDECREF(subargs);
430
431
-}
432
433
402
PyObject *
434
403
_Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObject *item)
435
404
@@ -440,67 +409,36 @@ _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObje
440
self);
441
442
item = _unpack_args(item);
443
- int is_tuple = PyTuple_Check(item);
444
- Py_ssize_t nitems = is_tuple ? PyTuple_GET_SIZE(item) : 1;
445
- PyObject **argitems = is_tuple ? &PyTuple_GET_ITEM(item, 0) : &item;
446
- Py_ssize_t varparam = nparams;
447
for (Py_ssize_t i = 0; i < nparams; i++) {
448
PyObject *param = PyTuple_GET_ITEM(parameters, i);
449
- if (Py_TYPE(param)->tp_iter) { // TypeVarTuple
450
- if (varparam < nparams) {
451
- Py_DECREF(item);
452
- return PyErr_Format(PyExc_TypeError,
453
- "More than one TypeVarTuple parameter in %S",
454
- self);
455
456
- varparam = i;
+ PyObject *prepare, *tmp;
+ if (_PyObject_LookupAttr(param, &_Py_ID(__typing_prepare_subst__), &prepare) < 0) {
+ Py_DECREF(item);
457
458
459
- PyObject *fillarg = NULL;
460
- Py_ssize_t vartuplearg = nitems;
461
- Py_ssize_t left = varparam;
462
- Py_ssize_t right = nparams - varparam - 1;
463
464
- for (Py_ssize_t i = 0; i < nitems; i++) {
465
- PyObject *arg = _get_unpacked_var_tuple_arg(argitems[i]);
466
- if (arg) {
467
- if (vartuplearg < nitems) {
468
- Py_DECREF(arg);
469
- Py_DECREF(fillarg);
470
471
472
- "More than one unpacked arbitrary-length tuple argument",
473
474
475
- vartuplearg = i;
476
- fillarg = arg;
+ if (prepare && prepare != Py_None) {
+ if (PyTuple_Check(item)) {
+ tmp = PyObject_CallFunction(prepare, "OO", self, item);
477
478
- else if (PyErr_Occurred()) {
479
- Py_XDECREF(fillarg);
480
+ else {
+ tmp = PyObject_CallFunction(prepare, "O(O)", self, item);
+ }
+ Py_DECREF(prepare);
+ Py_SETREF(item, tmp);
+ if (item == NULL) {
481
return NULL;
482
483
484
485
- assert(fillarg);
486
- left = Py_MIN(left, vartuplearg);
487
- right = Py_MIN(right, nitems - vartuplearg - 1);
488
489
- else if (left + right > nitems) {
490
491
492
- "Too few arguments for %R",
493
494
495
496
497
- if (nitems != nparams) {
498
499
500
- "Too %s arguments for %R; actual %zd, expected %zd",
501
- nitems > nparams ? "many" : "few",
502
- self, nitems, nparams);
503
+ int is_tuple = PyTuple_Check(item);
+ Py_ssize_t nitems = is_tuple ? PyTuple_GET_SIZE(item) : 1;
+ PyObject **argitems = is_tuple ? &PyTuple_GET_ITEM(item, 0) : &item;
436
+ if (nitems != nparams) {
437
438
+ return PyErr_Format(PyExc_TypeError,
439
+ "Too %s arguments for %R; actual %zd, expected %zd",
+ nitems > nparams ? "many" : "few",
+ self, nitems, nparams);
504
505
/* Replace all type variables (specified by parameters)
506
with corresponding values specified by argitems.
@@ -511,7 +449,6 @@ _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObje
511
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
512
PyObject *newargs = PyTuple_New(nargs);
513
if (newargs == NULL) {
514
515
Py_DECREF(item);
516
517
@@ -520,50 +457,26 @@ _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObje
520
int unpack = _is_unpacked_typevartuple(arg);
521
if (unpack < 0) {
522
Py_DECREF(newargs);
523
524
525
526
527
PyObject *subst;
528
if (_PyObject_LookupAttr(arg, &_Py_ID(__typing_subst__), &subst) < 0) {
529
530
531
532
533
534
if (subst) {
535
Py_ssize_t iparam = tuple_index(parameters, nparams, arg);
536
assert(iparam >= 0);
537
538
- Py_DECREF(subst);
539
- Py_DECREF(newargs);
540
541
542
- PyErr_SetString(PyExc_TypeError,
543
- "Substitution of bare TypeVarTuple is not supported");
544
545
546
547
548
549
550
- iparam += nitems - nparams;
551
552
553
554
555
556
557
- arg = PyObject_CallOneArg(subst, arg);
+ arg = PyObject_CallOneArg(subst, argitems[iparam]);
558
Py_DECREF(subst);
559
560
else {
561
- arg = subs_tvars(arg, parameters, argitems, nitems,
562
- varparam, left, right, fillarg);
+ arg = subs_tvars(arg, parameters, argitems, nitems);
563
564
if (arg == NULL) {
565
566
567
568
569
@@ -572,7 +485,6 @@ _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObje
572
&PyTuple_GET_ITEM(arg, 0), PyTuple_GET_SIZE(arg));
573
Py_DECREF(arg);
574
if (jarg < 0) {
575
576
577
578
@@ -583,7 +495,6 @@ _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObje
583
584
585
586
587
588
589