Skip to content

Commit 0641ada

Browse files
MSeifert04serhiy-storchaka
authored andcommitted
bpo-29800: Fix crashes in partial.__repr__ if the keys of partial.keywords are not strings (#649) (#672)
1 parent 59883bb commit 0641ada

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
@@ -387,6 +387,32 @@ def __getitem__(self, key):
387387
self.assertRaises(TypeError, f.__setstate__, BadSequence())
388388

389389

390+
def test_manually_adding_non_string_keyword(self):
391+
p = self.partial(capture)
392+
# Adding a non-string/unicode keyword to partial kwargs
393+
p.keywords[1234] = 'value'
394+
r = repr(p)
395+
self.assertIn('1234', r)
396+
self.assertIn("'value'", r)
397+
with self.assertRaises(TypeError):
398+
p()
399+
400+
def test_keystr_replaces_value(self):
401+
p = self.partial(capture)
402+
403+
class MutatesYourDict(object):
404+
def __str__(self):
405+
p.keywords[self] = ['sth2']
406+
return 'astr'
407+
408+
# Raplacing the value during key formatting should keep the original
409+
# value alive (at least long enough).
410+
p.keywords[MutatesYourDict()] = ['sth']
411+
r = repr(p)
412+
self.assertIn('astr', r)
413+
self.assertIn("['sth']", r)
414+
415+
390416
class TestPartialPy(TestPartial, unittest.TestCase):
391417
partial = staticmethod(py_functools.partial)
392418

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,6 +1348,7 @@ Federico Schwindt
13481348
Barry Scott
13491349
Steven Scott
13501350
Nick Seidenman
1351+
Michael Seifert
13511352
Žiga Seilnacht
13521353
Yury Selivanov
13531354
Fred Sells

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ Extension Modules
4343
Library
4444
-------
4545

46+
- bpo-29800: Fix crashes in partial.__repr__ if the keys of partial.keywords
47+
are not strings. Patch by Michael Seifert.
48+
4649
- bpo-29742: get_extra_info() raises exception if get called on closed ssl transport.
4750
Patch by Nikolay Kim.
4851

Modules/_functoolsmodule.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,11 @@ partial_repr(partialobject *pto)
234234
/* Pack keyword arguments */
235235
assert (PyDict_Check(pto->kw));
236236
for (i = 0; PyDict_Next(pto->kw, &i, &key, &value);) {
237-
Py_SETREF(arglist, PyUnicode_FromFormat("%U, %U=%R", arglist,
237+
/* Prevent key.__str__ from deleting the value. */
238+
Py_INCREF(value);
239+
Py_SETREF(arglist, PyUnicode_FromFormat("%U, %S=%R", arglist,
238240
key, value));
241+
Py_DECREF(value);
239242
if (arglist == NULL)
240243
goto done;
241244
}

0 commit comments

Comments
 (0)