@@ -57,13 +57,13 @@ static PyType_Slot placeholder_type_slots[] = {
57
57
};
58
58
59
59
static PyType_Spec placeholder_type_spec = {
60
- .name = "partial .Placeholder" ,
60
+ .name = "functools .Placeholder" ,
61
61
.basicsize = sizeof (placeholderobject ),
62
- .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
62
+ .flags = Py_TPFLAGS_DEFAULT |
63
63
Py_TPFLAGS_IMMUTABLETYPE |
64
64
Py_TPFLAGS_DISALLOW_INSTANTIATION ,
65
65
.slots = placeholder_type_slots
66
- };
66
+ }; // TODO> test: test.support.check_disallow_instantiation
67
67
68
68
69
69
typedef struct {
@@ -154,25 +154,27 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
154
154
Py_ssize_t nnp = 0 ;
155
155
Py_ssize_t nnargs = PyTuple_GET_SIZE (nargs );
156
156
PyObject * item ;
157
- if (nnargs > 0 ){
157
+ if (nnargs > 0 ) {
158
158
/* Trim placeholders from the end if needed */
159
159
Py_ssize_t nnargs_old = nnargs ;
160
160
for (; nnargs > 0 ; nnargs -- ) {
161
161
item = PyTuple_GET_ITEM (nargs , nnargs - 1 );
162
- if (!Py_Is (item , pto -> placeholder ))
162
+ if (!Py_Is (item , pto -> placeholder )) {
163
163
break ;
164
+ }
164
165
}
165
166
if (nnargs != nnargs_old ) {
166
167
PyObject * tmp = PyTuple_GetSlice (nargs , 0 , nnargs );
167
168
Py_DECREF (nargs );
168
169
nargs = tmp ;
169
170
}
170
171
/* Count placeholders */
171
- if (nnargs > 1 ){
172
- for (Py_ssize_t i = 0 ; i < nnargs - 1 ; i ++ ){
172
+ if (nnargs > 1 ) {
173
+ for (Py_ssize_t i = 0 ; i < nnargs - 1 ; i ++ ) {
173
174
item = PyTuple_GET_ITEM (nargs , i );
174
- if (Py_Is (item , pto -> placeholder ))
175
+ if (Py_Is (item , pto -> placeholder )) {
175
176
nnp ++ ;
177
+ }
176
178
}
177
179
}
178
180
}
@@ -185,12 +187,13 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
185
187
for (Py_ssize_t i = 0 , j = 0 ; i < nfargs ; i ++ ) {
186
188
if (i < npargs ) {
187
189
item = PyTuple_GET_ITEM (pargs , i );
188
- if ((j < nnargs ) & Py_Is (item , pto -> placeholder )){
190
+ if ((j < nnargs ) & Py_Is (item , pto -> placeholder )) {
189
191
item = PyTuple_GET_ITEM (nargs , j );
190
192
j ++ ;
191
193
pnp -- ;
192
194
}
193
- } else {
195
+ }
196
+ else {
194
197
item = PyTuple_GET_ITEM (nargs , j );
195
198
j ++ ;
196
199
}
@@ -200,10 +203,12 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
200
203
pto -> args = fargs ;
201
204
pto -> np = pnp + nnp ;
202
205
Py_DECREF (nargs );
203
- } else if (pargs == NULL ) {
206
+ }
207
+ else if (pargs == NULL ) {
204
208
pto -> args = nargs ;
205
209
pto -> np = nnp ;
206
- } else {
210
+ }
211
+ else {
207
212
pto -> args = PySequence_Concat (pargs , nargs );
208
213
pto -> np = pnp + nnp ;
209
214
Py_DECREF (nargs );
@@ -306,8 +311,9 @@ partial_vectorcall(partialobject *pto, PyObject *const *args,
306
311
}
307
312
Py_ssize_t np = pto -> np ;
308
313
if (nargs < np ) {
309
- PyErr_SetString (PyExc_TypeError ,
310
- "unfilled placeholders in 'partial' call" );
314
+ PyErr_Format (PyExc_TypeError ,
315
+ "missing positional arguments in 'partial' call; "
316
+ "expected at least %zd, got %zd" , np , nargs );
311
317
return NULL ;
312
318
}
313
319
@@ -358,19 +364,22 @@ partial_vectorcall(partialobject *pto, PyObject *const *args,
358
364
Py_ssize_t nargs_new ;
359
365
if (np ) {
360
366
nargs_new = pto_nargs + nargs - np ;
361
- Py_ssize_t j = 0 ; // Placeholder counter
367
+ Py_ssize_t j = 0 ; // New args index
362
368
for (Py_ssize_t i = 0 ; i < pto_nargs ; i ++ ) {
363
369
if (Py_Is (pto_args [i ], pto -> placeholder )){
364
370
memcpy (stack + i , args + j , 1 * sizeof (PyObject * ));
365
371
j += 1 ;
366
- } else {
372
+ }
373
+ else {
367
374
memcpy (stack + i , pto_args + i , 1 * sizeof (PyObject * ));
368
375
}
369
376
}
370
- if (nargs_total > np ){
371
- memcpy (stack + pto_nargs , args + np , (nargs_total - np ) * sizeof (PyObject * ));
377
+ assert (j == np );
378
+ if (nargs_total > np ) {
379
+ memcpy (stack + pto_nargs , args + j , (nargs_total - j ) * sizeof (PyObject * ));
372
380
}
373
- } else {
381
+ }
382
+ else {
374
383
nargs_new = pto_nargs + nargs ;
375
384
/* Copy to new stack, using borrowed references */
376
385
memcpy (stack , pto_args , pto_nargs * sizeof (PyObject * ));
@@ -411,8 +420,9 @@ partial_call(partialobject *pto, PyObject *args, PyObject *kwargs)
411
420
Py_ssize_t nargs = PyTuple_GET_SIZE (args );
412
421
Py_ssize_t np = pto -> np ;
413
422
if (nargs < np ) {
414
- PyErr_SetString (PyExc_TypeError ,
415
- "unfilled placeholders in 'partial' call" );
423
+ PyErr_Format (PyExc_TypeError ,
424
+ "missing positional arguments in 'partial' call; "
425
+ "expected at least %zd, got %zd" , np , nargs );
416
426
return NULL ;
417
427
}
418
428
@@ -445,25 +455,31 @@ partial_call(partialobject *pto, PyObject *args, PyObject *kwargs)
445
455
Py_ssize_t pto_nargs = PyTuple_GET_SIZE (pto -> args );
446
456
Py_ssize_t nargs_new = pto_nargs + nargs - np ;
447
457
args2 = PyTuple_New (nargs_new );
458
+ if (args2 == NULL ) {
459
+ Py_XDECREF (kwargs2 );
460
+ return NULL ;
461
+ }
448
462
PyObject * pto_args = pto -> args ;
449
463
PyObject * item ;
450
- Py_ssize_t j = 0 ; // Placeholder counter
464
+ Py_ssize_t j = 0 ; // New args index
451
465
for (Py_ssize_t i = 0 ; i < pto_nargs ; i ++ ) {
452
466
item = PyTuple_GET_ITEM (pto_args , i );
453
- if (Py_Is (item , pto -> placeholder )){
467
+ if (Py_Is (item , pto -> placeholder )) {
454
468
item = PyTuple_GET_ITEM (args , j );
455
469
j += 1 ;
456
470
}
457
471
PyTuple_SET_ITEM (args2 , i , item );
458
472
}
459
- if (nargs > np ){
473
+ assert (j == np );
474
+ if (nargs > np ) {
460
475
for (Py_ssize_t i = pto_nargs ; i < nargs_new ; i ++ ) {
461
476
item = PyTuple_GET_ITEM (args , j );
462
477
PyTuple_SET_ITEM (args2 , i , item );
463
478
j += 1 ;
464
479
}
465
480
}
466
- } else {
481
+ }
482
+ else {
467
483
/* Note: tupleconcat() is optimized for empty tuples */
468
484
args2 = PySequence_Concat (pto -> args , args );
469
485
}
@@ -491,7 +507,7 @@ static PyMemberDef partial_memberlist[] = {
491
507
"tuple of arguments to future partial calls" },
492
508
{"keywords" , _Py_T_OBJECT , OFF (kw ), Py_READONLY ,
493
509
"dictionary of keyword arguments to future partial calls" },
494
- {"np" , Py_T_PYSSIZET , OFF (np ), Py_READONLY ,
510
+ {"placeholder_count" , Py_T_PYSSIZET , OFF (np ), Py_READONLY ,
495
511
"number of placeholders" },
496
512
{"__weaklistoffset__" , Py_T_PYSSIZET ,
497
513
offsetof(partialobject , weakreflist ), Py_READONLY },
0 commit comments