]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-108732: include comprehension locals in frame.f_locals (#109026)
authorCarl Meyer <carl@oddbird.net>
Thu, 7 Sep 2023 14:56:43 +0000 (08:56 -0600)
committerGitHub <noreply@github.com>
Thu, 7 Sep 2023 14:56:43 +0000 (08:56 -0600)
Co-authored-by: Radislav Chugunov <52372310+chgnrdv@users.noreply.github.com>
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
Lib/test/test_listcomps.py
Misc/NEWS.d/next/Core and Builtins/2023-09-06-13-28-42.gh-issue-108732.I6DkEQ.rst [new file with mode: 0644]
Objects/frameobject.c

index bedd99b4a44fcba851910e9f2d97c183fd69313b..c1089574d71b025130ed09c6f011a78b170fa9bf 100644 (file)
@@ -596,6 +596,13 @@ class ListComprehensionTest(unittest.TestCase):
         """
         self._check_in_scopes(code, {"value": [1, None]})
 
+    def test_frame_locals(self):
+        code = """
+            val = [sys._getframe().f_locals for a in [0]][0]["a"]
+        """
+        import sys
+        self._check_in_scopes(code, {"val": 0}, ns={"sys": sys})
+
 
 __test__ = {'doctests' : doctests}
 
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-06-13-28-42.gh-issue-108732.I6DkEQ.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-06-13-28-42.gh-issue-108732.I6DkEQ.rst
new file mode 100644 (file)
index 0000000..94a143b
--- /dev/null
@@ -0,0 +1,2 @@
+Make iteration variables of module- and class-scoped comprehensions visible
+to pdb and other tools that use ``frame.f_locals`` again.
index 7017cc6c0e295fd28eb9a19f10cbfb058448d224..53764a41ca010a581ab5c98ddc52690e122bd2db 100644 (file)
@@ -25,10 +25,16 @@ static PyMemberDef frame_memberlist[] = {
 static PyObject *
 frame_getlocals(PyFrameObject *f, void *closure)
 {
-    if (PyFrame_FastToLocalsWithError(f) < 0)
+    if (f == NULL) {
+        PyErr_BadInternalCall();
         return NULL;
-    PyObject *locals = f->f_frame->f_locals;
-    return Py_NewRef(locals);
+    }
+    assert(!_PyFrame_IsIncomplete(f->f_frame));
+    PyObject *locals = _PyFrame_GetLocals(f->f_frame, 1);
+    if (locals) {
+        f->f_fast_as_locals = 1;
+    }
+    return locals;
 }
 
 int
@@ -1342,11 +1348,11 @@ PyFrame_GetVarString(PyFrameObject *frame, const char *name)
 int
 PyFrame_FastToLocalsWithError(PyFrameObject *f)
 {
-    assert(!_PyFrame_IsIncomplete(f->f_frame));
     if (f == NULL) {
         PyErr_BadInternalCall();
         return -1;
     }
+    assert(!_PyFrame_IsIncomplete(f->f_frame));
     int err = _PyFrame_FastToLocalsWithError(f->f_frame);
     if (err == 0) {
         f->f_fast_as_locals = 1;