Skip to content

Commit 53b2667

Browse files
MSeifert04serhiy-storchaka
authored andcommitted
bpo-29800: Fix crashes in partial.__repr__ if the keys of partial.keywords are not strings (#649) (#671)
1 parent faa2cc6 commit 53b2667

File tree

4 files changed

+34
-1
lines changed

4 files changed

+34
-1
lines changed

Lib/test/test_functools.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,32 @@ def test_attributes_unwritable(self):
402402
else:
403403
self.fail('partial object allowed __dict__ to be deleted')
404404

405+
def test_manually_adding_non_string_keyword(self):
406+
p = self.partial(capture)
407+
# Adding a non-string/unicode keyword to partial kwargs
408+
p.keywords[1234] = 'value'
409+
r = repr(p)
410+
self.assertIn('1234', r)
411+
self.assertIn("'value'", r)
412+
with self.assertRaises(TypeError):
413+
p()
414+
415+
def test_keystr_replaces_value(self):
416+
p = self.partial(capture)
417+
418+
class MutatesYourDict(object):
419+
def __str__(self):
420+
p.keywords[self] = ['sth2']
421+
return 'astr'
422+
423+
# Raplacing the value during key formatting should keep the original
424+
# value alive (at least long enough).
425+
p.keywords[MutatesYourDict()] = ['sth']
426+
r = repr(p)
427+
self.assertIn('astr', r)
428+
self.assertIn("['sth']", r)
429+
430+
405431
class TestPartialPy(TestPartial, unittest.TestCase):
406432
partial = py_functools.partial
407433

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,6 +1371,7 @@ Federico Schwindt
13711371
Barry Scott
13721372
Steven Scott
13731373
Nick Seidenman
1374+
Michael Seifert
13741375
Žiga Seilnacht
13751376
Yury Selivanov
13761377
Fred Sells

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ Core and Builtins
2929
Library
3030
-------
3131

32+
- bpo-29800: Fix crashes in partial.__repr__ if the keys of partial.keywords
33+
are not strings. Patch by Michael Seifert.
34+
3235
- bpo-29742: get_extra_info() raises exception if get called on closed ssl transport.
3336
Patch by Nikolay Kim.
3437

Modules/_functoolsmodule.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,11 @@ partial_repr(partialobject *pto)
250250
/* Pack keyword arguments */
251251
assert (PyDict_Check(pto->kw));
252252
for (i = 0; PyDict_Next(pto->kw, &i, &key, &value);) {
253-
Py_SETREF(arglist, PyUnicode_FromFormat("%U, %U=%R", arglist,
253+
/* Prevent key.__str__ from deleting the value. */
254+
Py_INCREF(value);
255+
Py_SETREF(arglist, PyUnicode_FromFormat("%U, %S=%R", arglist,
254256
key, value));
257+
Py_DECREF(value);
255258
if (arglist == NULL)
256259
goto done;
257260
}

0 commit comments

Comments
 (0)