Running tests/corekit/test_multidict.py and tests/project/test_public_api.py in one pytest process fails three tests that pass in either file alone. The cause is in tests/_support.py: bootstrap_core_modules() installs bare stub modules into sys.modules and never restores them, so a later test that introspects the real package sees the stubs instead.
Reproduced on untouched main
Measured on origin/main at 0c7f2b7c9 in a throwaway worktree with no changes of any kind, CPython 3.14.7, PYTHONSAFEPATH=1 and the worktree at PYTHONPATH:
$ python -m pytest tests/corekit/test_multidict.py tests/project/test_public_api.py -p no:cacheprovider -q
FAILED tests/project/test_public_api.py::PublicAPISurfaceTests::test_every_all_entry_resolves
FAILED tests/project/test_public_api.py::PublicAPISurfaceTests::test_every_public_package_declares_all
FAILED tests/project/test_public_api.py::PublicAPISurfaceTests::test_the_non_export_allowlist_is_tight
3 failed, 16 passed, 1 warning, 429 subtests passed in 1.47s
exit 1
Exit code read from a file, not from a pipeline.
The mechanism
tests/_support.py:187 bootstrap_core_modules() calls tests/_support.py:160 ensure_package(name, path), which leaves bare stub entries for pcapkit, pcapkit.corekit and pcapkit.utilities in sys.modules. Nothing removes them afterwards. test_public_api.py then imports the package to walk its __all__, gets the stubs, and finds no exports to check.
Why nobody has seen it
It is masked in a full-suite run, because some intervening test directory re-imports the real package between the two, repairing sys.modules by accident. It only surfaces when those two files are the whole selection — which is exactly what a developer does when narrowing to the area they are working on.
So the failure is real, is on main today, and is invisible to CI. It is also order-dependent, meaning it can appear or vanish from an unrelated change to the test selection, which is the worst property a test-infrastructure defect can have.
Not the defect reported in #660
#660 is the ProtocolBase stand-in being non-Generic (TypeError: type 'ProtocolBase' is not subscriptable), fixed by #662. That is a different mechanism and this is not fixed by #662 — the stub-restoration gap is separate from the Generic gap. Confirmed by reproducing with the test_multidict.py tests --deselected, and at untouched main.
Suggested fix
Restore sys.modules rather than only popping from it — a context manager or addCleanup that snapshots the affected keys and puts back exactly what was there, including absence. purge_modules currently pops without restoring, which is the same gap seen from the other side.
Found while working #661 / #667; not fixed there, since tests/_support.py is shared test infrastructure and the change wants its own review.
Running
tests/corekit/test_multidict.pyandtests/project/test_public_api.pyin one pytest process fails three tests that pass in either file alone. The cause is intests/_support.py:bootstrap_core_modules()installs bare stub modules intosys.modulesand never restores them, so a later test that introspects the real package sees the stubs instead.Reproduced on untouched
mainMeasured on
origin/mainat0c7f2b7c9in a throwaway worktree with no changes of any kind, CPython 3.14.7,PYTHONSAFEPATH=1and the worktree atPYTHONPATH:Exit code read from a file, not from a pipeline.
The mechanism
tests/_support.py:187bootstrap_core_modules()callstests/_support.py:160ensure_package(name, path), which leaves bare stub entries forpcapkit,pcapkit.corekitandpcapkit.utilitiesinsys.modules. Nothing removes them afterwards.test_public_api.pythen imports the package to walk its__all__, gets the stubs, and finds no exports to check.Why nobody has seen it
It is masked in a full-suite run, because some intervening test directory re-imports the real package between the two, repairing
sys.modulesby accident. It only surfaces when those two files are the whole selection — which is exactly what a developer does when narrowing to the area they are working on.So the failure is real, is on
maintoday, and is invisible to CI. It is also order-dependent, meaning it can appear or vanish from an unrelated change to the test selection, which is the worst property a test-infrastructure defect can have.Not the defect reported in #660
#660 is the
ProtocolBasestand-in being non-Generic(TypeError: type 'ProtocolBase' is not subscriptable), fixed by #662. That is a different mechanism and this is not fixed by #662 — the stub-restoration gap is separate from theGenericgap. Confirmed by reproducing with thetest_multidict.pytests--deselected, and at untouchedmain.Suggested fix
Restore
sys.modulesrather than only popping from it — a context manager oraddCleanupthat snapshots the affected keys and puts back exactly what was there, including absence.purge_modulescurrently pops without restoring, which is the same gap seen from the other side.Found while working #661 / #667; not fixed there, since
tests/_support.pyis shared test infrastructure and the change wants its own review.