Skip to content

Python 3.13.0b1: exec() does not populate locals() #118888

Closed

Description

@hroncok

Bug report

Bug description:

x.py

xxx = 118888

readx.py

def f():
    with open("x.py", encoding="utf-8") as f:
        exec(compile(f.read(), "x.py", "exec"))
    return locals()["xxx"]

print(f())

shell

$ python3.12 readx.py
118888

$ python3.13 readx.py
Traceback (most recent call last):
  File ".../readx.py", line 6, in <module>
    print(f())
          ~^^
  File ".../readx.py", line 4, in f
    return locals()["xxx"]
           ~~~~~~~~^^^^^^^
KeyError: 'xxx'

This breaks e.g. pillow 10.3.0 which has:

def get_version():
    version_file = "src/PIL/_version.py"
    with open(version_file, encoding="utf-8") as f:
        exec(compile(f.read(), version_file, "exec"))
    return locals()["__version__"]

In https://github.com/python-pillow/Pillow/blob/10.3.0/setup.py#L23

CPython versions tested on:

3.13

Operating systems tested on:

Linux

Linked PRs

Activity

  1. ncoghlan commented on May 30, 2024

    @ncoghlan
    Contributor

    Current plan for changes


    • Add this paragraph to the main PEP 667 description in the 3.13 "What's New?" doc:

    The change to the semantics of locals() in optimized scopes also affects the default behaviour of code execution functions that implicitly target locals() if no explicit namespace is provided (such as exec and eval). In previous versions, whether or not the changes could be accessed by calling locals() after the code finished execution was implementation dependent. In CPython specifically, such code would often appear to work as desired, but could sometimes fail in optimized scopes based on other code (including debuggers and code execution tracing tools) potentially resetting the shared snapshot in that scope. Now, the code will always run against an independent snapshot of locals() in optimized scopes, and hence the changes will never be visible in subsequent calls to locals(). To access the changes made in these cases, an explicit namespace reference must now be passed to the relevant function. Alternatively, it may make sense to switch over to using a higher level code execution API that returns the resulting code execution namespace (such as runpy.run_path).

    • Add this sentence to the porting note:

    Code execution functions that implicitly target locals() (such as exec and eval) must be passed an explicit namespace to access their results in an optimized scope.

  2. ncoghlan commented on May 31, 2024

    @ncoghlan
    Contributor

    No PR yet as I'll merge #119379 before making any further PEP 667 related updates.

  3. added a commit that references this issue on Jun 1, 2024
  4. added a commit that references this issue on Jun 1, 2024
  5. added a commit that references this issue on Jun 2, 2024
  6. added a commit that references this issue on Jun 5, 2024
  7. added a commit that references this issue on Jul 11, 2024
  8. added a commit that references this issue on Jul 17, 2024
  9. added a commit that references this issue on Nov 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.13only security fixes3.14bugs and security fixesdocsDocumentation in the Doc dir

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions