Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commiteffe8d4

Browse files
[3.14]gh-125028: Prohibit placeholders in partial keywords (GH-126062) (GH-133645)
(cherry picked from commitafed5f8)Co-authored-by: dgpb <3577712+dg-pb@users.noreply.github.com>
1 parentc6a56e3 commiteffe8d4

File tree

5 files changed

+37
-2
lines changed

5 files changed

+37
-2
lines changed

‎Doc/library/functools.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -403,8 +403,7 @@ The :mod:`functools` module defines the following functions:
403403
>>>remove_first_dear(message)
404404
'Hello, dear world!'
405405

406-
:data:`!Placeholder` has no special treatment when used in a keyword
407-
argument to:func:`!partial`.
406+
:data:`!Placeholder` cannot be passed to:func:`!partial` as a keyword argument.
408407

409408
..versionchanged::3.14
410409
Added support for:data:`Placeholder` in positional arguments.

‎Lib/functools.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,9 @@ def _partial_new(cls, func, /, *args, **keywords):
323323
"or a descriptor")
324324
ifargsandargs[-1]isPlaceholder:
325325
raiseTypeError("trailing Placeholders are not allowed")
326+
forvalueinkeywords.values():
327+
ifvalueisPlaceholder:
328+
raiseTypeError("Placeholder cannot be passed as a keyword argument")
326329
ifisinstance(func,base_cls):
327330
pto_phcount=func._phcount
328331
tot_args=func.args

‎Lib/test/test_functools.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
importcontextlib
2222
frominspectimportSignature
2323

24+
fromtest.supportimportALWAYS_EQ
2425
fromtest.supportimportimport_helper
2526
fromtest.supportimportthreading_helper
2627
fromtest.supportimportcpython_only
@@ -244,6 +245,13 @@ def test_placeholders(self):
244245
actual_args,actual_kwds=p('x','y')
245246
self.assertEqual(actual_args, ('x',0,'y',1))
246247
self.assertEqual(actual_kwds, {})
248+
# Checks via `is` and not `eq`
249+
# thus ALWAYS_EQ isn't treated as Placeholder
250+
p=self.partial(capture,ALWAYS_EQ)
251+
actual_args,actual_kwds=p()
252+
self.assertEqual(len(actual_args),1)
253+
self.assertIs(actual_args[0],ALWAYS_EQ)
254+
self.assertEqual(actual_kwds, {})
247255

248256
deftest_placeholders_optimization(self):
249257
PH=self.module.Placeholder
@@ -260,6 +268,17 @@ def test_placeholders_optimization(self):
260268
self.assertEqual(p2.args, (PH,0))
261269
self.assertEqual(p2(1), ((1,0), {}))
262270

271+
deftest_placeholders_kw_restriction(self):
272+
PH=self.module.Placeholder
273+
withself.assertRaisesRegex(TypeError,"Placeholder"):
274+
self.partial(capture,a=PH)
275+
# Passes, as checks via `is` and not `eq`
276+
p=self.partial(capture,a=ALWAYS_EQ)
277+
actual_args,actual_kwds=p()
278+
self.assertEqual(actual_args, ())
279+
self.assertEqual(len(actual_kwds),1)
280+
self.assertIs(actual_kwds['a'],ALWAYS_EQ)
281+
263282
deftest_construct_placeholder_singleton(self):
264283
PH=self.module.Placeholder
265284
tp=type(PH)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
:data:`functools.Placeholder` cannot be passed to:func:`functools.partial` as a keyword argument.

‎Modules/_functoolsmodule.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,19 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
196196
returnNULL;
197197
}
198198

199+
/* keyword Placeholder prohibition */
200+
if (kw!=NULL) {
201+
PyObject*key,*val;
202+
Py_ssize_tpos=0;
203+
while (PyDict_Next(kw,&pos,&key,&val)) {
204+
if (val==phold) {
205+
PyErr_SetString(PyExc_TypeError,
206+
"Placeholder cannot be passed as a keyword argument");
207+
returnNULL;
208+
}
209+
}
210+
}
211+
199212
/* check wrapped function / object */
200213
pto_args=pto_kw=NULL;
201214
intres=PyObject_TypeCheck(func,state->partial_type);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp