]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-118921: Add `copy()` method for `FrameLocalsProxy` (#118923)
authorTian Gao <gaogaotiantian@hotmail.com>
Fri, 10 May 2024 22:53:10 +0000 (15:53 -0700)
committerGitHub <noreply@github.com>
Fri, 10 May 2024 22:53:10 +0000 (15:53 -0700)
Lib/test/test_frame.py
Misc/NEWS.d/next/Core and Builtins/2024-05-10-19-54-18.gh-issue-118921.O4ztZG.rst [new file with mode: 0644]
Objects/frameobject.c

index 212255374bddd1c80fd27d039e189bc885fe69b6..aee8d374b22710a9c4d4af60875a9fe266ae39b3 100644 (file)
@@ -371,6 +371,15 @@ class TestFrameLocals(unittest.TestCase):
         f_locals['o'] = f_locals['k']
         self.assertEqual(o, 'a.b.c')
 
+    def test_copy(self):
+        x = 0
+        d = sys._getframe().f_locals
+        d_copy = d.copy()
+        self.assertIsInstance(d_copy, dict)
+        self.assertEqual(d_copy['x'], 0)
+        d_copy['x'] = 1
+        self.assertEqual(x, 0)
+
     def test_update_with_self(self):
         def f():
             f_locals = sys._getframe().f_locals
@@ -405,9 +414,6 @@ class TestFrameLocals(unittest.TestCase):
     def test_unsupport(self):
         x = 1
         d = sys._getframe().f_locals
-        with self.assertRaises(AttributeError):
-            d.copy()
-
         with self.assertRaises(TypeError):
             copy.copy(d)
 
diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-10-19-54-18.gh-issue-118921.O4ztZG.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-10-19-54-18.gh-issue-118921.O4ztZG.rst
new file mode 100644 (file)
index 0000000..39ccf47
--- /dev/null
@@ -0,0 +1 @@
+Add ``copy()`` method for ``FrameLocalsProxy`` which returns a snapshot ``dict`` for local variables.
index d7fcb1925d286c77e77aa42d1d1774fe049201ba..64fded85de1468029369b996907cd23539bfb44c 100644 (file)
@@ -637,6 +637,23 @@ framelocalsproxy_setdefault(PyObject* self, PyObject *const *args, Py_ssize_t na
     return result;
 }
 
+static PyObject*
+framelocalsproxy_copy(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+    PyObject* result = PyDict_New();
+
+    if (result == NULL) {
+        return NULL;
+    }
+
+    if (PyDict_Update(result, self) < 0) {
+        Py_DECREF(result);
+        return NULL;
+    }
+
+    return result;
+}
+
 static PyObject*
 framelocalsproxy_reversed(PyObject *self, void *Py_UNUSED(ignored))
 {
@@ -677,6 +694,8 @@ static PyMethodDef framelocalsproxy_methods[] = {
      NULL},
     {"__reversed__", _PyCFunction_CAST(framelocalsproxy_reversed),       METH_NOARGS,
      NULL},
+    {"copy",         _PyCFunction_CAST(framelocalsproxy_copy),           METH_NOARGS,
+     NULL},
     {"keys",         _PyCFunction_CAST(framelocalsproxy_keys),           METH_NOARGS,
      NULL},
     {"values",       _PyCFunction_CAST(framelocalsproxy_values),         METH_NOARGS,