Closed
Description
Likely related to #12112, discovered in jaraco/keyring#676, a new regression appears in pytest 8.1 relating to collection. Consider this minimal example:
draft @ cat > test_something.py
import foo
from foo.bar import baz
foo.bar.baz
draft @ mkdir -p foo/bar/baz
draft @ touch foo/__init__.py
draft @ touch foo/bar/__init__.py
draft @ touch foo/bar/baz/__init__.py
draft @ pip-run pytest -- -m pytest --import-mode importlib --doctest-modules
============================================================== test session starts ===============================================================
platform darwin -- Python 3.12.2, pytest-8.1.1, pluggy-1.4.0
rootdir: /Users/jaraco/draft
collected 0 items / 1 error
===================================================================== ERRORS =====================================================================
_______________________________________________________ ERROR collecting test_something.py _______________________________________________________
test_something.py:3: in <module>
foo.bar.baz
E AttributeError: module 'foo' has no attribute 'bar'
============================================================ short test summary info =============================================================
ERROR test_something.py - AttributeError: module 'foo' has no attribute 'bar'
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
================================================================ 1 error in 0.03s ================================================================
It seems that once the foo/bar/__init__.py
has been collected for doctesting, the collection of the tests in test_something will start to fail when foo
has no attribute bar
. Any of the following tweaks will bypass the failure:
- disable doctests
- pin to pytest<8.1
- use a different
import-mode
Something about the pytest discovery and import machinery is breaking the Python convention that importing a submodule causes the submodule to be added as an attribute of the parent module.