@@ -57,13 +57,13 @@ static PyType_Slot placeholder_type_slots[] = {
5757};
5858
5959static PyType_Spec placeholder_type_spec = {
60- .name = "partial .Placeholder" ,
60+ .name = "functools .Placeholder" ,
6161 .basicsize = sizeof (placeholderobject ),
62- .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
62+ .flags = Py_TPFLAGS_DEFAULT |
6363 Py_TPFLAGS_IMMUTABLETYPE |
6464 Py_TPFLAGS_DISALLOW_INSTANTIATION ,
6565 .slots = placeholder_type_slots
66- };
66+ }; // TODO> test: test.support.check_disallow_instantiation
6767
6868
6969typedef struct {
@@ -154,25 +154,27 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
154154 Py_ssize_t nnp = 0 ;
155155 Py_ssize_t nnargs = PyTuple_GET_SIZE (nargs );
156156 PyObject * item ;
157- if (nnargs > 0 ){
157+ if (nnargs > 0 ) {
158158 /* Trim placeholders from the end if needed */
159159 Py_ssize_t nnargs_old = nnargs ;
160160 for (; nnargs > 0 ; nnargs -- ) {
161161 item = PyTuple_GET_ITEM (nargs , nnargs - 1 );
162- if (!Py_Is (item , pto -> placeholder ))
162+ if (!Py_Is (item , pto -> placeholder )) {
163163 break ;
164+ }
164165 }
165166 if (nnargs != nnargs_old ) {
166167 PyObject * tmp = PyTuple_GetSlice (nargs , 0 , nnargs );
167168 Py_DECREF (nargs );
168169 nargs = tmp ;
169170 }
170171 /* 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 ++ ) {
173174 item = PyTuple_GET_ITEM (nargs , i );
174- if (Py_Is (item , pto -> placeholder ))
175+ if (Py_Is (item , pto -> placeholder )) {
175176 nnp ++ ;
177+ }
176178 }
177179 }
178180 }
@@ -185,12 +187,13 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
185187 for (Py_ssize_t i = 0 , j = 0 ; i < nfargs ; i ++ ) {
186188 if (i < npargs ) {
187189 item = PyTuple_GET_ITEM (pargs , i );
188- if ((j < nnargs ) & Py_Is (item , pto -> placeholder )){
190+ if ((j < nnargs ) & Py_Is (item , pto -> placeholder )) {
189191 item = PyTuple_GET_ITEM (nargs , j );
190192 j ++ ;
191193 pnp -- ;
192194 }
193- } else {
195+ }
196+ else {
194197 item = PyTuple_GET_ITEM (nargs , j );
195198 j ++ ;
196199 }
@@ -200,10 +203,12 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
200203 pto -> args = fargs ;
201204 pto -> np = pnp + nnp ;
202205 Py_DECREF (nargs );
203- } else if (pargs == NULL ) {
206+ }
207+ else if (pargs == NULL ) {
204208 pto -> args = nargs ;
205209 pto -> np = nnp ;
206- } else {
210+ }
211+ else {
207212 pto -> args = PySequence_Concat (pargs , nargs );
208213 pto -> np = pnp + nnp ;
209214 Py_DECREF (nargs );
@@ -306,8 +311,9 @@ partial_vectorcall(partialobject *pto, PyObject *const *args,
306311 }
307312 Py_ssize_t np = pto -> np ;
308313 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 );
311317 return NULL ;
312318 }
313319
@@ -358,19 +364,22 @@ partial_vectorcall(partialobject *pto, PyObject *const *args,
358364 Py_ssize_t nargs_new ;
359365 if (np ) {
360366 nargs_new = pto_nargs + nargs - np ;
361- Py_ssize_t j = 0 ; // Placeholder counter
367+ Py_ssize_t j = 0 ; // New args index
362368 for (Py_ssize_t i = 0 ; i < pto_nargs ; i ++ ) {
363369 if (Py_Is (pto_args [i ], pto -> placeholder )){
364370 memcpy (stack + i , args + j , 1 * sizeof (PyObject * ));
365371 j += 1 ;
366- } else {
372+ }
373+ else {
367374 memcpy (stack + i , pto_args + i , 1 * sizeof (PyObject * ));
368375 }
369376 }
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 * ));
372380 }
373- } else {
381+ }
382+ else {
374383 nargs_new = pto_nargs + nargs ;
375384 /* Copy to new stack, using borrowed references */
376385 memcpy (stack , pto_args , pto_nargs * sizeof (PyObject * ));
@@ -411,8 +420,9 @@ partial_call(partialobject *pto, PyObject *args, PyObject *kwargs)
411420 Py_ssize_t nargs = PyTuple_GET_SIZE (args );
412421 Py_ssize_t np = pto -> np ;
413422 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 );
416426 return NULL ;
417427 }
418428
@@ -445,25 +455,31 @@ partial_call(partialobject *pto, PyObject *args, PyObject *kwargs)
445455 Py_ssize_t pto_nargs = PyTuple_GET_SIZE (pto -> args );
446456 Py_ssize_t nargs_new = pto_nargs + nargs - np ;
447457 args2 = PyTuple_New (nargs_new );
458+ if (args2 == NULL ) {
459+ Py_XDECREF (kwargs2 );
460+ return NULL ;
461+ }
448462 PyObject * pto_args = pto -> args ;
449463 PyObject * item ;
450- Py_ssize_t j = 0 ; // Placeholder counter
464+ Py_ssize_t j = 0 ; // New args index
451465 for (Py_ssize_t i = 0 ; i < pto_nargs ; i ++ ) {
452466 item = PyTuple_GET_ITEM (pto_args , i );
453- if (Py_Is (item , pto -> placeholder )){
467+ if (Py_Is (item , pto -> placeholder )) {
454468 item = PyTuple_GET_ITEM (args , j );
455469 j += 1 ;
456470 }
457471 PyTuple_SET_ITEM (args2 , i , item );
458472 }
459- if (nargs > np ){
473+ assert (j == np );
474+ if (nargs > np ) {
460475 for (Py_ssize_t i = pto_nargs ; i < nargs_new ; i ++ ) {
461476 item = PyTuple_GET_ITEM (args , j );
462477 PyTuple_SET_ITEM (args2 , i , item );
463478 j += 1 ;
464479 }
465480 }
466- } else {
481+ }
482+ else {
467483 /* Note: tupleconcat() is optimized for empty tuples */
468484 args2 = PySequence_Concat (pto -> args , args );
469485 }
@@ -491,7 +507,7 @@ static PyMemberDef partial_memberlist[] = {
491507 "tuple of arguments to future partial calls" },
492508 {"keywords" , _Py_T_OBJECT , OFF (kw ), Py_READONLY ,
493509 "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 ,
495511 "number of placeholders" },
496512 {"__weaklistoffset__" , Py_T_PYSSIZET ,
497513 offsetof(partialobject , weakreflist ), Py_READONLY },
0 commit comments