Skip to content

frame.f_locals for list/dict/set comprehension in module/class scope doesn't contain iteration variables #108732

Closed

Description

@chgnrdv

Bug report

Checklist

  • I am confident this is a bug in CPython, not a bug in a third-party project
  • I have searched the CPython issue tracker,
    and am confident this bug has not been reported before

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Output from running 'python -VV' on the command line:

Python 3.13.0a0 (heads/main:dd32611f4f, Aug 31 2023, 20:23:23) [GCC 10.2.1 20210110]

A clear and concise description of the bug:

The following assertion fails with PEP 709 (c3b595e):

import sys
f_locs = None
[f_locs := sys._getframe().f_locals for a in range(1)]
assert 'a' in f_locs

This was discovered when trying to inspect listcomp iteration variable under pdb, as it makes inspection of these variables impossible:

> /home/radislav/projects/cpython/listcomp.py(1)<module>()
-> [print(a) for a in range(1)]
(Pdb) s
0
> /home/radislav/projects/cpython/listcomp.py(1)<module>()
-> [print(a) for a in range(1)]
(Pdb) print(a)
*** NameError: name 'a' is not defined
(Pdb) s
/home/radislav/projects/cpython/listcomp.py:1: RuntimeWarning: assigning None to unbound local 'a'
  [print(a) for a in range(1)]
--Return--
> /home/radislav/projects/cpython/listcomp.py(1)<module>()->None
-> [print(a) for a in range(1)]

As I can see, it happens because iteration vars are now stored in "fast hidden locals" that aren't included into frame->f_locals on _PyFrame_FastToLocalsWithError(frame) call, and thus are not accessible through PyFrameObject f_locals attribute.

cc @carljm

Linked PRs

Activity

  1. self-assigned this
    on Aug 31, 2023
  2. added 3 commits that reference this issue on Sep 6, 2023
  3. carljm commented on Sep 6, 2023

    @carljm
    Member

    Thanks for the report! Attached PR fixes this. Sorry I wasn't able to get the PR up and merged in time for 3.12.0.rc2; was traveling over the long (US) holiday weekend. I think this probably means the fix will need to wait until 3.12.1, unless @Yhg1s wants to merge it between rc2 and final .0. I think the fix is low-risk, but the bug is also an edge case that is unlikely to affect a lot of users, so I think either way is probably OK.

  4. added a commit that references this issue on Sep 7, 2023
  5. added a commit that references this issue on Sep 7, 2023
  6. added a commit that references this issue on Sep 12, 2023
  7. P403n1x87 commented on Sep 20, 2023

    @P403n1x87
    Contributor

    Just stumbled upon this and I have noticed something similar with frame stacks. Not sure whether this is considered expected in 3.12

    ❯ python3.12 -c "import sys;from traceback import print_stack; [print_stack() for _ in range(1)]"
      File "<string>", line 1, in <module>
    
    ❯ python3.11 -c "import sys;from traceback import print_stack; [print_stack() for _ in range(1)]"
      File "<string>", line 1, in <module>
      File "<string>", line 1, in <listcomp>
    

    Essentially, frame stacks in 3.12 seem to be missing list (and probably other, not tested) comprehensions.

  8. carljm commented on Sep 20, 2023

    @carljm
    Member

    @P403n1x87 Yes, that's expected and called out in PEP 709 as an expected impact. There are not language guarantees about what frames show up in Python frame stacks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

type-bugAn unexpected behavior, bug, or error

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions