8000 restrict keyword placeholders · python/cpython@a04c14f · GitHub
[go: up one dir, main page]

Skip to content

Commit a04c14f

Browse files
committed
restrict keyword placeholders
1 parent d217592 commit a04c14f

File tree

3 files changed

+27
-15
lines changed

3 files changed

+27
-15
lines changed

Lib/functools.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,10 @@ class partial:
342342
def __new__(cls, func, /, *args, **keywords):
343343
if not callable(func):
344344
raise TypeError("the first argument must be callable")
345+
if keywords:
346+
for v in keywords.values():
347+
if v is Placeholder:
348+
raise TypeError("keyword Placeholders are not allowed")
345349
if isinstance(func, partial):
346350
pto_phcount = func._phcount
347351
tot_args = func.args

Lib/test/test_functools.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,12 @@ def test_placeholders_optimization(self):
254254
self.assertEqual(p2.args, (PH, 0))
255255
self.assertEqual(p2(1), ((1, 0), {}))
256256

257+
def test_placeholders_kw_restriction(self):
258+
PH = self.module.Placeholder
259+
exc_string = 'keyword Placeholders are not allowed'
260+
with self.assertRaisesRegex(TypeError, exc_string):
261+
self.partial(capture, a=PH)
262+
257263
def test_construct_placeholder_singleton(self):
258264
PH = self.module.Placeholder
259265
tp = type(PH)

Modules/_functoolsmodule.c

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -290,29 +290,31 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
290290

291291
/* process keywords */
292292
if (pto_kw == NULL || PyDict_GET_SIZE(pto_kw) == 0) {
293-
if (kw == NULL) {
294-
pto->kw = PyDict_New();
295-
}
296-
else if (Py_REFCNT(kw) == 1) {
297-
pto->kw = Py_NewRef(kw);
298-
}
299-
else {
300-
pto->kw = PyDict_Copy(kw);
301-
}
293+
pto->kw = PyDict_New();
302294
}
303295
else {
304296
pto->kw = PyDict_Copy(pto_kw);
305-
if (kw != NULL && pto->kw != NULL) {
306-
if (PyDict_Merge(pto->kw, kw, 1) != 0) {
297+
if (pto->kw == NULL) {
298+
Py_DECREF(pto);
299+
return NULL;
300+
}
301+
}
302+
if (kw != NULL && pto->kw != NULL) {
303+
PyObject *key, *val;
304+
Py_ssize_t pos = 0;
305+
while (PyDict_Next(kw, &pos, &key, &val)) {
306+
if (val == phold) {
307+
Py_DECREF(pto);
308+
PyErr_SetString(PyExc_TypeError,
309+
"keyword Placeholders are not allowed");
310+
return NULL;
311+
}
312+
if (PyDict_SetItem(pto->kw, key, val)) {
307313
Py_DECREF(pto);
308314
return NULL;
309315
}
310316
}
311317
}
312-
if (pto->kw == NULL) {
313-
Py_DECREF(pto);
314-
return NULL;
315-
}
316318

317319
partial_setvectorcall(pto);
318320
return (PyObject *)pto;

0 commit comments

Comments
 (0)
0