GitHub - flying-sheep/pytest-doctest-import-twice (original) (raw)

pytest reproducer

When using the following together, pytest 7.4.0 creates multiple instances of modules instead of reusing already-executed ones. The bug triggers in pytest’s collection phase.

Necessary for the bug to trigger:

Run with e.g.

hatch run pytest

or if you like typing

python -m virtualenv .venv; source .venv/bin/activate; pip install -e .; pytest

No matter if you opt to install in dev mode like this, specify PYTHONPATH, or install regularly, the bug is reproducible in any case.

how it works

The module in __init__.py gets created and executed twice, but when each instance executes from .singleton import MyVindictiveSingleton, that reuses the same instance of the submodule.

flowchart LR A[init.py] -->|imports| C(singleton.py) B[init.py] -->|imports| C(singleton.py)

Loading

tracebacks

The two tracebacks are almost identical, but show that a cached version of a submodule is used (fewer frozen importlib._bootstrap frames).

It’s also possible to put some code in conftest.py or a plugin and have the second execution there.

File "/lib/python3.11/site-packages/_pytest/pathlib.py", line 538, in import_path spec.loader.exec_module(mod) # type: ignore[union-attr] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "", line 940, in exec_module File "", line 241, in _call_with_frames_removed File "/pytest_doctest_import_twice/init.py", line 1, in from .singleton import MyVindictiveSingleton File "", line 1178, in _find_and_load File "", line 1128, in _find_and_load_unlocked File "", line 241, in _call_with_frames_removed File "", line 1178, in _find_and_load File "", line 1149, in _find_and_load_unlocked File "", line 690, in _load_unlocked File "", line 940, in exec_module File "", line 241, in _call_with_frames_removed File "/pytest_doctest_import_twice/init.py", line 3, in instance = MyVindictiveSingleton() ^^^^^^^^^^^^^^^^^^^^^^^

File "/lib/python3.11/site-packages/_pytest/pathlib.py", line 538, in import_path spec.loader.exec_module(mod) # type: ignore[union-attr] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "", line 940, in exec_module File "", line 241, in _call_with_frames_removed File "/pytest_doctest_import_twice/init.py", line 3, in instance = MyVindictiveSingleton() ^^^^^^^^^^^^^^^^^^^^^^^