FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Names that have been resolved are not consistently removed from sys.lazy_modules · Issue #155695 · python/cpython · GitHub

Repository navigation

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

Description

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

Activity

prithviraj-chaudhuri commented on Aug 28, 2026

picnixz commented on Sep 2, 2026

prithviraj-chaudhuri commented on Sep 9, 2026

DavidCEllis commented on Sep 10, 2026

ContributorAuthor

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.

psyedgufran-svg commented on Sep 10, 2026

picnixz commented on Sep 10, 2026

picnixz commented on Sep 10, 2026

Member

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

johnslavik commented on Sep 10, 2026

Member

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

johnslavik commented on Sep 11, 2026

Member

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.

self-assigned this
on Sep 11, 2026

brittanyrey commented on Sep 17, 2026

Contributor

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.

johnslavik commented on Sep 17, 2026

Member

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

added 5 commits that reference this issue on Sep 26, 2026
added a commit that references this issue on Oct 2, 2026
added a commit that references this issue on Oct 2, 2026
added a commit that references this issue on Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions


Back | FazBrowse Home | New Git URL