Skip to content

Commit

Permalink
restrict keyword placeholders
Browse files Browse the repository at this point in the history
  • Loading branch information
dg-pb committed Oct 4, 2024
1 parent d217592 commit a04c14f
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 15 deletions.
4 changes: 4 additions & 0 deletions Lib/functools.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,10 @@ class partial:
def __new__(cls, func, /, *args, **keywords):
if not callable(func):
raise TypeError("the first argument must be callable")
if keywords:
for v in keywords.values():
if v is Placeholder:
raise TypeError("keyword Placeholders are not allowed")
if isinstance(func, partial):
pto_phcount = func._phcount
tot_args = func.args
Expand Down
6 changes: 6 additions & 0 deletions Lib/test/test_functools.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,12 @@ def test_placeholders_optimization(self):
self.assertEqual(p2.args, (PH, 0))
self.assertEqual(p2(1), ((1, 0), {}))

def test_placeholders_kw_restriction(self):
PH = self.module.Placeholder
exc_string = 'keyword Placeholders are not allowed'
with self.assertRaisesRegex(TypeError, exc_string):
self.partial(capture, a=PH)

def test_construct_placeholder_singleton(self):
PH = self.module.Placeholder
tp = type(PH)
Expand Down
32 changes: 17 additions & 15 deletions Modules/_functoolsmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,29 +290,31 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)

/* process keywords */
if (pto_kw == NULL || PyDict_GET_SIZE(pto_kw) == 0) {
if (kw == NULL) {
pto->kw = PyDict_New();
}
else if (Py_REFCNT(kw) == 1) {
pto->kw = Py_NewRef(kw);
}
else {
pto->kw = PyDict_Copy(kw);
}
pto->kw = PyDict_New();
}
else {
pto->kw = PyDict_Copy(pto_kw);
if (kw != NULL && pto->kw != NULL) {
if (PyDict_Merge(pto->kw, kw, 1) != 0) {
if (pto->kw == NULL) {
Py_DECREF(pto);
return NULL;
}
}
if (kw != NULL && pto->kw != NULL) {
PyObject *key, *val;
Py_ssize_t pos = 0;
while (PyDict_Next(kw, &pos, &key, &val)) {
if (val == phold) {
Py_DECREF(pto);
PyErr_SetString(PyExc_TypeError,
"keyword Placeholders are not allowed");
return NULL;
}
if (PyDict_SetItem(pto->kw, key, val)) {
Py_DECREF(pto);
return NULL;
}
}
}
if (pto->kw == NULL) {
Py_DECREF(pto);
return NULL;
}

partial_setvectorcall(pto);
return (PyObject *)pto;
Expand Down

0 comments on commit a04c14f

Please sign in to comment.