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 — Names that have been resolved are not consistently removed from sys.lazy_modules · Issue #155695 · python/cpython

Names that have been resolved are not consistently removed from sys.lazy_modules #155695

New issue
Copy link
New issue
Copy link
Closed
Closed
Names that have been resolved are not consistently removed from sys.lazy_modules#155695
Copy link
Assignees
johnslavik
Labels
interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)release-blockertopic-lazy-importstype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Description

@DavidCEllis
DavidCEllis
opened on Aug 13, 2026
Issue body actions

Bug report

Bug description:

I'm slightly hesitant to raise this because there's still discussion over what sys.lazy_modules should be. The documentation for sys.lazy_modules currently states:

When a lazily imported module is accessed for the first time, its name is removed from this set.

In at least two cases I'm aware of names are not being removed. Names may also not be modules, but I'd consider that a documentation issue while I believe the failure to remove names is a bug.


Names of modules that have previously been resolved will be re-added, but not removed when resolved again.

import sys
mods = sys.lazy_modules.copy()
def get_lazy():
    return sorted(sys.lazy_modules - mods)

lazy import x  # added
print(get_lazy())
x  # removed
print(get_lazy())
lazy import x  # added again
x  # not removed
print(get_lazy())
['x']
[]
['x']

Here I think the issue is adding x back to sys.lazy_modules when it's already in sys.modules.


Names that are not modules are not removed:

import sys
mods = sys.lazy_modules.copy()
def get_lazy():
    return sorted(sys.lazy_modules - mods)

lazy from x import X
print(get_lazy())
X
print(get_lazy())  # Should be empty
['x', 'x.X']
['x.X']

CPython versions tested on:

3.15, CPython main branch

Operating systems tested on:

No response

Linked PRs

  • gh-155695: Remove resolved names from sys.lazy_modules more consistently #157714
  • [3.15] gh-155695: Remove resolved names from sys.lazy_modules more consistently (GH-157714) #158607

Activity

  1. DavidCEllis
    added
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    topic-lazy-imports
    on Aug 13, 2026
  2. picnixz
    added
    interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)
    on Aug 13, 2026
  3. prithviraj-chaudhuri commented on Aug 28, 2026

    @prithviraj-chaudhuri
    prithviraj-chaudhuri
    on Aug 28, 2026 · Hidden as outdated
    show commentMore actions
  4. picnixz commented on Sep 2, 2026

    @picnixz
    picnixz
    on Sep 2, 2026 · Hidden as outdated
    show commentMore actions
  5. prithviraj-chaudhuri commented on Sep 9, 2026

    @prithviraj-chaudhuri
    prithviraj-chaudhuri
    on Sep 9, 2026 · Hidden as outdated
    show commentMore actions
  6. DavidCEllis commented on Sep 10, 2026

    @DavidCEllis
    DavidCEllis
    on Sep 10, 2026
    ContributorAuthor
    More actions

    I'm not working on a PR for this right now. As @picnixz said though, there's no clear answer on what to do though.

    The documentation has been changed since I made this issue and now states:

    When a lazily imported module is accessed for the first time, its name is typically removed from this set.

    So technically it now matches the documentation but I don't think this is good behaviour that we should have.

  7. johnslavik
    assigned
    johnslavik
    and unassigned
    johnslavik
    on Sep 10, 2026
  8. psyedgufran-svg commented on Sep 10, 2026

    @psyedgufran-svg
    psyedgufran-svg
    on Sep 10, 2026 · Hidden as outdated
    show commentMore actions
  9. picnixz commented on Sep 10, 2026

    @picnixz
    picnixz
    on Sep 10, 2026 · Hidden as outdated
    show commentMore actions
  10. picnixz commented on Sep 10, 2026

    @picnixz
    picnixz
    on Sep 10, 2026
    Member
    More actions

    cc @DinoV @pablogsal for what they think we should do here (and whether we should do anything as well)

    Reacted by Bartosz Sławecki
  11. johnslavik commented on Sep 10, 2026

    @johnslavik
    johnslavik
    on Sep 10, 2026
    Member
    More actions

    I see two ways to go here:

    1. Immediately return cached sys.modules entry in lazy import x
    2. Clean up sys.lazy_modules in cached paths (regular import or cached lazy import x + cached lazy from x import X)

    For (1), plain lazy import x currently creates a proxy and adds x to sys.lazy_modules, even if the module is already cached. Accessing the proxy later calls the ordinary import machinery, whose cache lookup returns the existing module.

    lazy from x import X already has an eager cache fast path, i.e. if x is cached in sys.modules and that dictionary contains X, it returns that attribute directly instead of creating an attribute proxy.

    I prefer we check the cache in lazy import x and return early too, since lazy from x import X already does that.

    For (2), cleanup currently happens when a module is loaded (not returned from cache). _find_and_load_unlocked() calls _imp._set_lazy_attributes() after loading, and that function discards the loaded module's name from sys.lazy_modules.

    lazy from registers the parent module name and the qualified imported name, such as x.X before taking its eager attribute fast path, so consequently:

    • If resolving X loads x, cleanup removes x, but an ordinary attribute entry x.X remains.
    • If X is a submodule actually loaded as x.X, its module-loading path removes x.X.
    • If x and its attribute X are already available, the eager fast path returns X without removing either entry.

    I believe we can fix both (1) and (2).

    Reacted by Petr Viktorin and David Ellis
  12. johnslavik commented on Sep 11, 2026

    @johnslavik
    johnslavik
    on Sep 11, 2026
    Member
    More actions

    Judging by the fact that we already do cache lazy from x import X, I think it's correct to do the same in the simpler case, lazy import x. We should definitely clean up sys.lazy_modules in cached paths, so there is something to do regardless. I'll start making a patch, we can iterate. EAFP.

    Reacted by Brittany Reynoso
  13. johnslavik
    self-assigned this
    on Sep 11, 2026
  14. brittanyrey commented on Sep 17, 2026

    @brittanyrey
    brittanyrey
    on Sep 17, 2026
    Contributor
    More actions

    Hi, I'm working with @pablogsal to tie up loose ends around Lazy Imports ahead of the 3.15 final cut.
    In the sake of time, I put together a PR to address both parts (1) and (2) of the issue. If you already have a change that you prefer--no hard feelings! That works too.

  15. johnslavik commented on Sep 17, 2026

    @johnslavik
    johnslavik
    on Sep 17, 2026
    Member
    More actions

    @brittanyrey No worries at all, I hope I helped here. I can help reviewing, ping me anytime. Thanks for taking over and working on this.

    Reacted by Brittany Reynoso
  16. pablogsal
    added 5 commits that reference this issue on Sep 26, 2026

    pythongh-155695: Track cached exports without invoking spec callbacks

    44ebbaa

    pythongh-155695: Read initialization flags without materializing spec…

    5fa018a

    pythongh-155695: Keep lazy-module state inspection conservative

    ce8c909

    pythongh-155695: Simplify lazy module bookkeeping

    83ac500

    pythongh-155695: Preserve import behavior in lazy module tracking

    ad36b56
  17. hugovk
    added
    release-blocker
    on Sep 30, 2026
  18. github-project-automation
    added this to Release and Deferred blockers 🚫on Sep 30, 2026
  19. github-project-automation
    moved this to Todo in Release and Deferred blockers 🚫on Sep 30, 2026
  20. hugovk
    added a commit that references this issue on Oct 2, 2026

    gh-155695: Remove resolved names from sys.lazy_modules more consisten…

    be87a85
  21. Yhg1s
    added a commit that references this issue on Oct 2, 2026

    [3.15] gh-155695: Remove resolved names from sys.lazy_modules more co…

    c2eb1a8
  22. hugovk
    closed this as completedon Oct 2, 2026
  23. Kronuz
    added a commit that references this issue on Oct 5, 2026

    [3.15] pythongh-155695: Remove resolved names from sys.lazy_modules m…

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

Metadata

Metadata

Assignees

  • @johnslavik
    johnslavik

Labels

interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)release-blockertopic-lazy-importstype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Projects

  • Release and Deferred blockers 🚫
    Status
    Done
    Show more project fields

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.