GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Python 3.13.0b1: exec() does not populate locals() · Issue #118888 · python/cpython

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

New issue
Copy link
New issue
Copy link
Closed
#119893
Closed
Python 3.13.0b1: exec() does not populate locals()#118888
#119893
Copy link
Labels
3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixesdocsDocumentation in the Doc dirDocumentation in the Doc dir

Description

@hroncok
hroncok
opened on May 10, 2024
Issue body actions

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

  • gh-118888: Further PEP 667 docs updates #119893
  • [3.13] gh-118888: Further PEP 667 docs updates (gh-119893) #119894

Activity

Next
  1. hroncok
    added
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    on May 10, 2024
  2. Eclips4 commented on May 10, 2024

    @Eclips4
    Eclips4
    on May 10, 2024
    Member
    More actions

    Bisected to b034f14
    cc @gaogaotiantian

  3. Eclips4
    added
    3.13only security fixesonly security fixes
    3.14bugs and security fixesbugs and security fixes
    on May 10, 2024
  4. gaogaotiantian commented on May 10, 2024

    @gaogaotiantian
    gaogaotiantian
    on May 10, 2024
    Member
    More actions

    This is an expected and intentional behavior change due to PEP 667. locals() now has a clear semantic when called inside a function - a snapshot of the local variables, and xxx (or __version__) is not one of them.

    I won't even consider this is "breaking" as the docs clearly states:

    modifications to the default locals dictionary should not be attempted. Pass an explicit locals dictionary if you need to see effects of the code on locals after function exec() returns.

    So this is an illegal usage that happens to work in a favored way to begin with.

    If you want the result of the local changes, pass in an explicit dictionary:

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

    I'm aware that this might be a bit inconvenience to the library maintainers, but this is the right way to go and we are making efforts to make locals() more consistent and predictable.

    Reacted by Kirill Podoprigora
    Reacted by Alexander Karpinsky
  5. terryjreedy
    added
    docsDocumentation in the Doc dirDocumentation in the Doc dir
    and removed
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    on May 10, 2024
  6. terryjreedy commented on May 10, 2024

    @terryjreedy
    terryjreedy
    on May 10, 2024
    Member
    More actions

    It it true that the 3.12 docs say that readx.py should not be expected to work. But it did then and previously, even though not now. What's New 3.13 only says

    PEP 667: FrameType.f_locals when used in a function now returns a write-through proxy to the frame’s locals, rather than a dict. See the PEP for corresponding C API changes and deprecations.

    From this, I would not expect changes in how locals() behaves, in particular in the effect of exec bindings. I think this should be mention.

    Even the Python subsection of the PEP's Back Compatibility section says nothing. It only mentions a couple of things that do not change.

    Reacted by Kirill Podoprigora and caoanan
  7. gaogaotiantian commented on May 11, 2024

    @gaogaotiantian
    gaogaotiantian
    on May 11, 2024
    Member
    More actions

    We are aware that the docs are not fully ready for beta 1, but this behavior is described in detail in locals. https://docs.python.org/3.13/library/functions.html#locals . We can add some notes to exec or eval or whatsnews, but the key change is actually on the locals() function, which the first version of docs is written for.

  8. hugovk commented on May 25, 2024

    @hugovk
    hugovk
    on May 25, 2024
    Member
    More actions

    Can this be closed now the docs were updated in #119201?

  9. terryjreedy commented on May 25, 2024

    @terryjreedy
    terryjreedy
    on May 25, 2024
    Member
    More actions

    @ncoghlan Does #119201 make this obsolete?

  10. ncoghlan commented on May 30, 2024

    @ncoghlan
    ncoghlan
    on May 30, 2024
    Contributor
    More actions

    Yeah, the function level snapshot behaviour is now covered in the What's New porting guide: https://docs.python.org/3.13/whatsnew/3.13.html#changes-in-the-python-api

    It is also mentioned in a versionchanged note on exec itself: https://docs.python.org/3.13/library/functions.html#exec

    The general write-up of PEP 667 also mentions locals() first before covering FrameType.f_locals: https://docs.python.org/3.13/whatsnew/3.13.html#whatsnew313-locals-semantics

    The most minimal change to fix this kind of exec invocation is to pass explicit target namespaces as suggested in #118888 (comment) (this exec call is already implicitly being called with separate globals and locals namespaces, so explicitly calling it that way won't change the behaviour of the executed code)

    Alternatively, for the examples given, https://docs.python.org/3/library/runpy.html#runpy.run_path is a better tool when the task is "run the Python file at this location and return its top level namespace" (it will respect Python source encoding declarations properly, while explicitly opening the files as utf-8 ignores them).

  11. ncoghlan
    closed this as completedon May 30, 2024
  12. ncoghlan commented on May 30, 2024

    @ncoghlan
    ncoghlan
    on May 30, 2024
    Contributor
    More actions

    Considering this further, I'm thinking it may be worth tweaking the text in "What's New" a bit, as somebody reading even the updated What's New entry might not make the leap from "the mutation semantics of locals() have changed in optimised scopes" to "the semantics of exec(), eval(), and other code execution APIs that default to targeting locals() have changed in optimised scopes".

  13. ncoghlan
    reopened this on May 30, 2024
  14. 4 remaining items

  15. miss-islington
    added a commit that references this issue on Jun 1, 2024

    pythongh-118888: Further PEP 667 docs updates (pythongh-119893)

    4760402
  16. ncoghlan
    added a commit that references this issue on Jun 2, 2024

    [3.13] gh-118888: Further PEP 667 docs updates (gh-119894)

    36ca00f
  17. barneygale
    added a commit that references this issue on Jun 5, 2024

    pythongh-118888: Further PEP 667 docs updates (pythongh-119893)

    1e0b92e
  18. estyxx
    added a commit that references this issue on Jul 17, 2024

    pythongh-118888: Further PEP 667 docs updates (pythongh-119893)

    ed4f826
  19. mikem23
    added a commit that references this issue on Aug 14, 2024

    setup.py: Fix version retrieval on Python 3.13+

    7dd9a83
  20. Shonas301
    added a commit that references this issue on Oct 26, 2024

    Update `setup.py` to accommodate `Python3.13.0`

    9b8c3cb
  21. markmentovai
    added 3 commits that reference this issue on Nov 5, 2024

    py-Pillow: add py313 subport

    80ac06c

    py-Pillow: add py313 subport

    da8fd95

    py-Pillow: add py313 subport

    bbcda4b
  22. reneeotten
    added a commit that references this issue on Nov 7, 2024

    py-Pillow: add py313 subport

    fc849ac
  23. RA80533
    added 2 commits that reference this issue on Feb 24, 2025

    Fix get_version for Python 3.13

    332f864

    Fix get_version for Python 3.13

    a724c77
  24. petewarden
    added a commit that references this issue on May 12, 2025

    Fixes __version__ not found error with Python 3.13 (see python/cpytho…

    5f13ad9
  25. zzzeek
    added a commit that references this issue on Jun 3, 2025

    fix locals() writable, does not seem to work on py313

    7e7eca8
  26. petewarden
    added a commit that references this issue on Aug 8, 2026

    Fixes __version__ not found error with Python 3.13 (see python/cpytho…

    cb617ff
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 fixesonly security fixes3.14bugs and security fixesbugs and security fixesdocsDocumentation in the Doc dirDocumentation in the Doc dir

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.