-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
gh-119127: functools.partial placeholders #119827
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
ee7333c
8bcc462
c67c9b4
680d900
9591ff5
067e938
8af20b3
607a0b1
f55801e
5894145
3722e07
a79c2af
12aaa72
92c767b
496a9d2
38d9c11
707b957
14b38ca
32bca19
8576493
a3fd2d6
0852993
6fea348
caec6e8
115b8c5
3f5f00b
202c929
2c16d38
400ff55
8ccc38f
e7c82c7
c9b7ef3
e59d711
7bfc591
7957a97
8aaee6a
fe8e0ad
00dd80e
d352cfa
9038ed5
49b8c71
bc1fdbd
3067221
1185510
266b4fa
dd58a12
5971fbb
9033650
d31e5d1
a3d39b0
9e4c5df
16f12f8
82dd600
f9cb653
d255524
404044e
800217b
38ee450
11f47db
3c872bd
fd16189
a6c6ef2
1c8d73e
a8bd3ae
70e47ed
2eacf5e
f78d8d3
0a8640e
6e3d282
66c305d
14bf68c
ee642d5
8d6c28e
8744bcb
b896470
4881ae6
c3ad7d9
5e5d484
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,27 +43,118 @@ get_functools_state(PyObject *module) | |
/* partial object **********************************************************/ | ||
|
||
|
||
typedef struct { | ||
PyObject_HEAD | ||
} placeholderobject; | ||
/* | ||
Placeholder is an object that can be used to signal that positional | ||
argument place is empty when using `partial` class | ||
*/ | ||
dg-pb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
PyObject* | ||
Py_GetPlaceholder(void); | ||
|
||
static PyObject * | ||
placeholder_repr(PyObject *op) | ||
{ | ||
return PyUnicode_FromString("Placeholder"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe use In particular, you could also decide whether the singleton should be implemented (and exported) using the same logic as for (Sorry, I only remembered about that singleton now and not before) |
||
} | ||
|
||
PyDoc_STRVAR(placeholder_doc, "placeholder for partial arguments"); | ||
static void | ||
placeholder_dealloc(PyObject* placeholder) | ||
{ | ||
/* This should never get called, but we also don't want to SEGV if | ||
* we accidentally decref None out of existence. Instead, | ||
* since None is an immortal object, re-set the reference count. | ||
dg-pb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
*/ | ||
_Py_SetImmortal(placeholder); | ||
} | ||
|
||
static PyObject * | ||
placeholder_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) | ||
{ | ||
if (PyTuple_GET_SIZE(args) || (kwargs && PyDict_GET_SIZE(kwargs))) { | ||
PyErr_SetString(PyExc_TypeError, "PlaceholderType takes no arguments"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could use |
||
return NULL; | ||
} | ||
return Py_GetPlaceholder(); | ||
} | ||
|
||
static PyType_Slot placeholder_type_slots[] = { | ||
{Py_tp_doc, (void *)placeholder_doc}, | ||
{0, 0} | ||
static int | ||
placeholder_bool(PyObject *v) | ||
{ | ||
PyErr_SetString(PyExc_TypeError, | ||
"Placeholder should not be used in a boolean context"); | ||
return -1; | ||
} | ||
|
||
static PyNumberMethods placeholder_as_number = { | ||
.nb_bool = placeholder_bool, | ||
}; | ||
|
||
static PyType_Spec placeholder_type_spec = { | ||
.name = "functools.Placeholder", | ||
.basicsize = sizeof(placeholderobject), | ||
.flags = Py_TPFLAGS_DEFAULT | | ||
Py_TPFLAGS_IMMUTABLETYPE | | ||
Py_TPFLAGS_DISALLOW_INSTANTIATION, | ||
.slots = placeholder_type_slots | ||
}; // TODO> test: test.support.check_disallow_instantiation | ||
|
||
PyDoc_STRVAR(placeholder_doc, | ||
"PlaceholderType()\n" | ||
"--\n\n" | ||
"The type of the Placeholder singleton."); | ||
|
||
PyTypeObject _PyPlaceholder_Type = { | ||
PyVarObject_HEAD_INIT(&PyType_Type, 0) | ||
"PlaceholderType", | ||
0, | ||
0, | ||
placeholder_dealloc, /*tp_dealloc*/ /*never called*/ | ||
0, /*tp_vectorcall_offset*/ | ||
0, /*tp_getattr*/ | ||
0, /*tp_setattr*/ | ||
0, /*tp_as_async*/ | ||
placeholder_repr, /*tp_repr*/ | ||
&placeholder_as_number, /*tp_as_number*/ | ||
0, /*tp_as_sequence*/ | ||
0, /*tp_as_mapping*/ | ||
0, /*tp_hash */ | ||
0, /*tp_call */ | ||
0, /*tp_str */ | ||
0, /*tp_getattro */ | ||
0, /*tp_setattro */ | ||
0, /*tp_as_buffer */ | ||
Py_TPFLAGS_DEFAULT, /*tp_flags */ | ||
placeholder_doc, /*tp_doc */ | ||
0, /*tp_traverse */ | ||
0, /*tp_clear */ | ||
0, /*tp_richcompare */ | ||
0, /*tp_weaklistoffset */ | ||
0, /*tp_iter */ | ||
0, /*tp_iternext */ | ||
0, /*tp_methods */ | ||
0, /*tp_members */ | ||
0, /*tp_getset */ | ||
0, /*tp_base */ | ||
0, /*tp_dict */ | ||
0, /*tp_descr_get */ | ||
0, /*tp_descr_set */ | ||
0, /*tp_dictoffset */ | ||
0, /*tp_init */ | ||
0, /*tp_alloc */ | ||
placeholder_new, /*tp_new */ | ||
}; | ||
|
||
PyObject _Py_PlaceholderStruct = _PyObject_HEAD_INIT(&_PyPlaceholder_Type); | ||
|
||
#define PY_CONSTANT_PLACEHOLDER 0 | ||
|
||
static PyObject* constants[] = { | ||
&_Py_PlaceholderStruct, // PY_CONSTANT_PLACEHOLDER | ||
}; | ||
|
||
PyObject* | ||
Py_GetPlaceholder(void) | ||
{ | ||
if (PY_CONSTANT_PLACEHOLDER < Py_ARRAY_LENGTH(constants)) { | ||
return constants[PY_CONSTANT_PLACEHOLDER]; | ||
} | ||
else { | ||
PyErr_BadInternalCall(); | ||
return NULL; | ||
} | ||
} | ||
|
||
|
||
typedef struct { | ||
|
@@ -150,7 +241,7 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw) | |
return NULL; | ||
} | ||
|
||
pto->placeholder = (PyObject *) state->placeholder_type; | ||
pto->placeholder = Py_GetPlaceholder(); | ||
Py_ssize_t nnp = 0; | ||
Py_ssize_t nnargs = PyTuple_GET_SIZE(nargs); | ||
PyObject *item; | ||
|
@@ -598,18 +689,19 @@ partial_repr(partialobject *pto) | |
static PyObject * | ||
partial_reduce(partialobject *pto, PyObject *unused) | ||
{ | ||
return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn, | ||
pto->args, pto->kw, | ||
return Py_BuildValue("O(O)(OOOnO)", Py_TYPE(pto), pto->fn, pto->fn, | ||
pto->args, pto->kw, pto->np, | ||
pto->dict ? pto->dict : Py_None); | ||
} | ||
|
||
static PyObject * | ||
partial_setstate(partialobject *pto, PyObject *state) | ||
{ | ||
PyObject *fn, *fnargs, *kw, *dict; | ||
Py_ssize_t np; | ||
|
||
if (!PyTuple_Check(state) || | ||
!PyArg_ParseTuple(state, "OOOO", &fn, &fnargs, &kw, &dict) || | ||
!PyArg_ParseTuple(state, "OOOnO", &fn, &fnargs, &kw, &np, &dict) || | ||
!PyCallable_Check(fn) || | ||
!PyTuple_Check(fnargs) || | ||
(kw != Py_None && !PyDict_Check(kw))) | ||
|
@@ -640,10 +732,10 @@ partial_setstate(partialobject *pto, PyObject *state) | |
dict = NULL; | ||
else | ||
Py_INCREF(dict); | ||
|
||
Py_SETREF(pto->fn, Py_NewRef(fn)); | ||
Py_SETREF(pto->args, fnargs); | ||
Py_SETREF(pto->kw, kw); | ||
pto->np = np; | ||
Py_XSETREF(pto->dict, dict); | ||
partial_setvectorcall(pto); | ||
Py_RETURN_NONE; | ||
|
@@ -1626,6 +1718,7 @@ static PyType_Spec lru_cache_type_spec = { | |
|
||
/* module level code ********************************************************/ | ||
|
||
|
||
dg-pb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
PyDoc_STRVAR(_functools_doc, | ||
"Tools that operate on functions."); | ||
|
||
|
@@ -1644,15 +1737,9 @@ _functools_exec(PyObject *module) | |
return -1; | ||
} | ||
|
||
state->placeholder_type = (PyTypeObject *)PyType_FromModuleAndSpec(module, | ||
&placeholder_type_spec, NULL); | ||
if (state->placeholder_type == NULL) { | ||
return -1; | ||
} | ||
if (PyModule_AddType(module, state->placeholder_type) < 0) { | ||
if (PyModule_AddObject(module, "Placeholder", Py_GetPlaceholder()) < 0) { | ||
return -1; | ||
} | ||
|
||
state->partial_type = (PyTypeObject *)PyType_FromModuleAndSpec(module, | ||
&partial_type_spec, NULL); | ||
if (state->partial_type == NULL) { | ||
|
@@ -1697,7 +1784,6 @@ _functools_traverse(PyObject *module, visitproc visit, void *arg) | |
{ | ||
_functools_state *state = get_functools_state(module); | ||
Py_VISIT(state->kwd_mark); | ||
Py_VISIT(state->placeholder_type); | ||
Py_VISIT(state->partial_type); | ||
Py_VISIT(state->keyobject_type); | ||
Py_VISIT(state->lru_list_elem_type); | ||
|
@@ -1709,7 +1795,6 @@ _functools_clear(PyObject *module) | |
{ | ||
_functools_state *state = get_functools_state(module); | ||
Py_CLEAR(state->kwd_mark); | ||
Py_CLEAR(state->placeholder_type); | ||
Py_CLEAR(state->partial_type); | ||
Py_CLEAR(state->keyobject_type); | ||
Py_CLEAR(state->lru_list_elem_type); | ||
|
Uh oh!
There was an error while loading. Please reload this page.