Description
Describe the bug
If an implicit namespace package (directory without __init__.py
) exists within a source module and is not imported, coverage won't discover it or report it as uncovered.
I discovered this on Django project where an app had an idiomatic management.commands
submodule without intermediate __init__.py
files. This had two levels of implicit namespace packages, but it also happens with just one (what would be just management
).
To Reproduce
Worked example:
$ coverage --version
Coverage.py, version 5.2.1 with C extension
Full documentation is at https://coverage.readthedocs.io
$ python --version
Python 3.8.3
$ tree example
example
├── management
│ └── submodule2.py
└── submodule.py
1 directory, 2 files
$ cat example/submodule.py
x = 1
$ cat example/management/submodule2.py
y = 2
$ cat test.py
import example.submodule
$ coverage erase && coverage run --source example -m test && coverage report
Name Stmts Miss Cover
------------------------------------------
example/submodule.py 1 0 100%
Expected behavior
I'd expect example/management/submodule2.py
to be discovered as uncovered. Adding an __init__.py
to management
makes coverage discover it:
$ touch example/management/__init__.py
$ coverage erase && coverage run --source example -m test && coverage report
Name Stmts Miss Cover
------------------------------------------------------
example/management/__init__.py 0 0 100%
example/management/submodule2.py 1 1 0%
example/submodule.py 1 0 100%
------------------------------------------------------
TOTAL 2 1 50%
Additional context
Implicit namespace packages "just work" with Python 3, and many new developers create them on purpose or accidentally.
Django itself has moved to, and then back from, implicit namespace packages for management commands: https://groups.google.com/g/django-developers/c/GVHMH2ciAnk/m/7RzvMIzyAQAJ . So there are at least some users who believe "__init__.py
files are no longer needed".