gh-108732: include comprehension locals in frame.f_locals (#109026)

Co-authored-by: Radislav Chugunov <52372310+chgnrdv@users.noreply.github.com>
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
This commit is contained in:
Carl Meyer 2023-09-07 08:56:43 -06:00 committed by GitHub
parent b72251de93
commit f2584eade3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 19 additions and 4 deletions

View file

@ -596,6 +596,13 @@ class ListComprehensionTest(unittest.TestCase):
""" """
self._check_in_scopes(code, {"value": [1, None]}) 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} __test__ = {'doctests' : doctests}

View file

@ -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.

View file

@ -25,10 +25,16 @@ static PyMemberDef frame_memberlist[] = {
static PyObject * static PyObject *
frame_getlocals(PyFrameObject *f, void *closure) frame_getlocals(PyFrameObject *f, void *closure)
{ {
if (PyFrame_FastToLocalsWithError(f) < 0) if (f == NULL) {
PyErr_BadInternalCall();
return NULL; 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 int
@ -1342,11 +1348,11 @@ PyFrame_GetVarString(PyFrameObject *frame, const char *name)
int int
PyFrame_FastToLocalsWithError(PyFrameObject *f) PyFrame_FastToLocalsWithError(PyFrameObject *f)
{ {
assert(!_PyFrame_IsIncomplete(f->f_frame));
if (f == NULL) { if (f == NULL) {
PyErr_BadInternalCall(); PyErr_BadInternalCall();
return -1; return -1;
} }
assert(!_PyFrame_IsIncomplete(f->f_frame));
int err = _PyFrame_FastToLocalsWithError(f->f_frame); int err = _PyFrame_FastToLocalsWithError(f->f_frame);
if (err == 0) { if (err == 0) {
f->f_fast_as_locals = 1; f->f_fast_as_locals = 1;