Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pytest: how to work around missing __init__.py in the tests folder?

Tags:

python

pytest

I am storing all the pytest files in the tests sub-directory under the project root. There is no __init__.py in that directory or above and pytest tests/test_a.py works as expected. I can also run pytest test_a.py directly from within the tests folder.

|--<project_root>
+---[tests]
    test_a.py
    base.py
    config.py
    conftest.py

The test class in test_a.py inherits from base.py. Now, the problem is that because of the missing __init__.py the IDE tooling does not work and the imports cannot be resolved. Adding __init__.py under the tests resolves all import errors in the IDE, but tests won't run anymore with pytest test_a.py because py.test fails to import conftest.py.

In my conftest.py I have the following imports:

from config import HOST_URL_DEFAULT, USER, PASSWORD

which results in:

ModuleNotFoundError: No module named 'config'
ERROR: could not load /project_root/tests/conftest.py

Is there a way to solve this so that both IDE tooling works and pytest keeps working? I would like to avoid using dot imports, if possible.

Update: After reading this answer I think I am finally starting to understand a bit more how python imports work.

like image 762
ccpizza Avatar asked Jun 11 '18 11:06

ccpizza


1 Answers

Add __init__.py and use a relative or absolute import in conftest.py:

# relative
from .config import HOST_URL_DEFAULT, USER, PASSWORD
# absolute
from tests.config import HOST_URL_DEFAULT, USER, PASSWORD

In a package (identified by __init__.py), you need unambiguous import paths. Using unqualified imports (from config import ...) depends on PYTHONPATH or sys.modules including your package root - this is generally not robust and should be avoided as it circumvents the package infrastructure.

What you have here (config.py used by other modules) is a package. Treat it as one.


pytest does not discourage the use of a test package with an __init__.py! There are veritable use cases for this - such as yours.

What pytest does discourage is having a source package and test package in the same source root. However, that means you should move your source package, not your test package!

mysource/  # root directory for both mypackage and mytests
+- mypackage/  # should be src/mypackage instead!
   +- __init__.py
   +- abcd.py
+- mytests
   +- __init__.py
   +- tests_abcd.py  # ``from mypackage import abcd`` imports from source

The problem is that running mytests means that mypackage is importable from source as well. That is, your tests are working on your source package, not your installed package. If there are any errors in your installation procedure, testing will not catch it. See the blog linked in the pytest docs for details.

like image 117
MisterMiyagi Avatar answered Nov 11 '22 14:11

MisterMiyagi