Skip to content

Lib/importlib: Ensure stale empty python module directories don't break the build #120492

Closed

Description

@kanavin

Bug report

Bug description:

The Yocto project has been seeing mysterious build failures that were traced down to stale empty python module directories left behind by previous module versions:
https://bugzilla.yoctoproject.org/show_bug.cgi?id=14816

We are carrying the following patch to address the issue (it both ignores the empty directories, and looks at directories in deterministic sorted order):

--- a/Lib/importlib/metadata/__init__.py
+++ b/Lib/importlib/metadata/__init__.py
@@ -710,7 +710,14 @@ class Lookup:
         self.infos = FreezableDefaultDict(list)
         self.eggs = FreezableDefaultDict(list)
 
-        for child in path.children():
+        for child in sorted(path.children()):
+            childpath = pathlib.Path(path.root, child)
+            try:
+                if childpath.is_dir() and not any(childpath.iterdir()):
+                    # Empty directories aren't interesting
+                    continue
+            except PermissionError:
+                continue
             low = child.lower()
             if low.endswith((".dist-info", ".egg-info")):
                 # rpartition is faster than splitext and suitable for this purpose.

We'd like to discuss with upstream if such a fix is appropriate and will be taken as a proper pull request.

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Linked PRs

Activity

  1. eli-schwartz commented on Jun 18, 2024

    @eli-schwartz
    Contributor

    I would at least cross-post to https://github.com/python/importlib_metadata/issues given that primary development of importlib.metadata happens there.

  2. self-assigned this
    on Jun 27, 2024
  3. jaraco commented on Sep 12, 2024

    @jaraco
    Member

    This issue will be addressed by syncing with the latest importlib_metadata.

  4. added
    stdlibStandard Library Python modules in the Lib/ directory
    on Sep 13, 2024
  5. rossburton commented on Apr 29, 2025

    @rossburton
    Contributor

    Another fun edgecase: if a .dist-info directory exists but is empty it gets returned by importlib.metadata.distributions() but as there is no metadata you end up with lots of Nones:

    * Getting build dependencies for wheel...
    Traceback (most recent call last):
      File "/work/ross/build/tmp/work/aarch64-linux/python3-meson-python-native/0.17.1/recipe-sysroot-native/usr/lib/python3.13/site-packages/build/__main__.py", line 178, in _handle_build_error
        yield
      File "/work/ross/build/tmp/work/aarch64-linux/python3-meson-python-native/0.17.1/recipe-sysroot-native/usr/lib/python3.13/site-packages/build/__main__.py", line 429, in main
        built = build_call(
            args.srcdir,
        ...<5 lines>...
            args.installer,
        )
      File "/work/ross/build/tmp/work/aarch64-linux/python3-meson-python-native/0.17.1/recipe-sysroot-native/usr/lib/python3.13/site-packages/build/__main__.py", line 238, in build_package
        out = _build(isolation, srcdir, outdir, distribution, config_settings, skip_dependency_check, installer)
      File "/work/ross/build/tmp/work/aarch64-linux/python3-meson-python-native/0.17.1/recipe-sysroot-native/usr/lib/python3.13/site-packages/build/__main__.py", line 172, in _build
        return _build_in_current_env(srcdir, outdir, distribution, config_settings, skip_dependency_check)
      File "/work/ross/build/tmp/work/aarch64-linux/python3-meson-python-native/0.17.1/recipe-sysroot-native/usr/lib/python3.13/site-packages/build/__main__.py", line 151, in _build_in_current_env
        missing = builder.check_dependencies(distribution, config_settings or {})
      File "/work/ross/build/tmp/work/aarch64-linux/python3-meson-python-native/0.17.1/recipe-sysroot-native/usr/lib/python3.13/site-packages/build/_builder.py", line 243, in check_dependencies
        return {u for d in dependencies for u in check_dependency(d)}
                                                 ~~~~~~~~~~~~~~~~^^^
      File "/work/ross/build/tmp/work/aarch64-linux/python3-meson-python-native/0.17.1/recipe-sysroot-native/usr/lib/python3.13/site-packages/build/_util.py", line 53, in check_dependency
        if req.specifier and not req.specifier.contains(dist.version, prereleases=True):
                                 ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/work/ross/build/tmp/work/aarch64-linux/python3-meson-python-native/0.17.1/recipe-sysroot-native/usr/lib/python3.13/site-packages/packaging/specifiers.py", line 917, in contains
        item = Version(item)
      File "/work/ross/build/tmp/work/aarch64-linux/python3-meson-python-native/0.17.1/recipe-sysroot-native/usr/lib/python3.13/site-packages/packaging/version.py", line 200, in __init__
        match = self._regex.search(version)
    TypeError: expected string or bytes-like object, got 'NoneType'
    

    Should importlib.metadata.distributions return a Distribution object for empty .dist-info directories?

  6. jaraco commented on Aug 14, 2025

    @jaraco
    Member

    Should importlib.metadata.distributions return a Distribution object for empty .dist-info directories?

    My instinct - yes. The .dist-info directory is the primary indicator for the distribution existing. So even if it's not a valid one, it is present and thus should be reflected in the object model.

  7. added 2 commits that reference this issue on Aug 14, 2025
  8. jaraco commented on Aug 15, 2025

    @jaraco
    Member

    With the merged PR, this issue can be closed.

    The fix is in Python 3.15. Users requiring the future behavior on older Pythons should use importlib_metadata >= 8.2.

  9. added a commit that references this issue on Aug 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

stdlibStandard Library Python modules in the Lib/ directorytopic-importlibtype-bugAn unexpected behavior, bug, or error

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions