@@ -37,6 +37,8 @@ To pull up one entry: `grep -n '^N\. ' references/gotchas/testing-and-shadowing.
3737 wraps ` sys.executable ` in a profiler launcher and every later subprocess test silently skips
3838 or times out; a collected demo script can leave a repeating ` SIGALRM ` that kills pytest at
3939 exit; ` sys._base_executable ` helpers escape the test venv.
40+ - ** 612** — A same-run ` importlib.metadata ` check can shadow to a checkout's leftover
41+ ` egg-info ` instead of the installed wheel, not just ` import <pkg> ` (extends gotcha 25).
4042
4143---
4244
@@ -643,3 +645,35 @@ To pull up one entry: `grep -n '^N\. ' references/gotchas/testing-and-shadowing.
643645 elsewhere with a warning. With the memory tests skipping, the patch adding `riscv64`
644646 looked unnecessary; with the polluter isolated they fail without it and pass with it.
645647
648+ 612. **A same-run `importlib.metadata` check can shadow to a checkout's leftover `egg-info`
649+ instead of the installed wheel, not just `import <pkg>` (extends gotcha 25; the pyscf
650+ case).** Gotcha 25's shadowing is about `import <pkg>` resolving to the source tree
651+ because cwd is on `sys.path[0]`. The same trigger breaks a *metadata* check that never
652+ imports the package at all: a build step's `pip wheel . --no-clean` (or any PEP 517
653+ `build_wheel` invoked against a local directory — build isolation only isolates the
654+ build *environment*, not where setuptools' `egg_info` command writes) leaves
655+ `<pkg>.egg-info/` sitting in the checkout root, and that checkout root is the very
656+ directory a *later, separate* `docker run -w <checkout>` reuses as cwd for the test
657+ step. `python -c "..."` prepends `''` (cwd) to `sys.path` unconditionally, so
658+ `importlib.metadata.distribution('<pkg>')`/`.files('<pkg>')` resolves the stale
659+ `egg-info` there before ever consulting the properly `pip install`ed `*.dist-info` in
660+ site-packages — and classic egg-info metadata predates PEP 639, so it has no
661+ `licenses/` subdirectory at all. A licence-file assertion built the gotcha-44 way
662+ (`{p.name for p in importlib.metadata.files('<pkg>') if '.dist-info/licenses/' in
663+ str(p)}`) then asserts against an empty set with no exception raised — reads exactly
664+ like the licence files never made it into the wheel, when the wheel (and its
665+ `auditwheel`-repaired copy, RECORD included) is fine.
666+ - **Verify by relocating, not by inspecting auditwheel.** `auditwheel repair` was the
667+ obvious suspect (it does rewrite `RECORD` and retag the wheel) but is not the culprit
668+ here: repairing a minimal dummy wheel with a `licenses/*` glob and inspecting the
669+ output directly shows the `dist-info/licenses/` files and their `RECORD` entries
670+ untouched. The tell that it's shadowing instead: `importlib.metadata.distribution(
671+ '<pkg>')._path` names the local `egg-info`, not the site-packages `dist-info`, and
672+ the file list it returns includes checkout-only names like `setup.py`/`pyproject.toml`
673+ that the installed wheel never ships.
674+ - **Fix by moving the check past a `cd` to a directory with no `<pkg>` on disk** — `/tmp`
675+ inside the test container is fresh per `docker run` and already the convention this
676+ same script uses one step later, before `import pyscf`, for the plainer gotcha-25
677+ reason. Run the metadata check *after* that `cd`, not before it: writing the check
678+ first (chronologically, before the later `import <pkg>` smoke test was added) is why
679+ it alone stayed exposed.
0 commit comments