bpo-29532: Altering a kwarg dictionary passed to functools.partial() (#190)
authorSerhiy Storchaka <storchaka@gmail.com>
Mon, 20 Feb 2017 12:04:30 +0000 (14:04 +0200)
committerGitHub <noreply@github.com>
Mon, 20 Feb 2017 12:04:30 +0000 (14:04 +0200)
no longer affects a partial object after creation.

Lib/test/test_functools.py
Misc/NEWS
Modules/_functoolsmodule.c

index 63fe83e5dbd6028ecb4d68bbf74a4f43deac14e9..612ca17a60bc8cd90cbea0f32f059151a3c5e600 100644 (file)
@@ -90,6 +90,15 @@ class TestPartial:
         p(b=7)
         self.assertEqual(d, {'a':3})
 
+    def test_kwargs_copy(self):
+        # Issue #29532: Altering a kwarg dictionary passed to a constructor
+        # should not affect a partial object after creation
+        d = {'a': 3}
+        p = self.partial(capture, **d)
+        self.assertEqual(p(), ((), {'a': 3}))
+        d['a'] = 5
+        self.assertEqual(p(), ((), {'a': 3}))
+
     def test_arg_combinations(self):
         # exercise special code paths for zero args in either partial
         # object or the caller
index 0c2a5730e31388fbcf725811f28816724da097f7..fa7e3f5a5e7f0690040785485c810420f24809d0 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -232,6 +232,9 @@ Extension Modules
 Library
 -------
 
+- bpo-29532: Altering a kwarg dictionary passed to functools.partial()
+  no longer affects a partial object after creation.
+
 - bpo-22807: Add uuid.SafeUUID and uuid.UUID.is_safe to relay information from
   the platform about whether generated UUIDs are generated with a
   multiprocessing safe method.
index 4170883368f953363bcf07606f3877264792b73c..c8565054c903de93d64ae7fc7e8ef652e47693c3 100644 (file)
@@ -88,10 +88,13 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
         if (kw == NULL) {
             pto->kw = PyDict_New();
         }
-        else {
+        else if (Py_REFCNT(kw) == 1) {
             Py_INCREF(kw);
             pto->kw = kw;
         }
+        else {
+            pto->kw = PyDict_Copy(kw);
+        }
     }
     else {
         pto->kw = PyDict_Copy(pkw);