I try to organized my Python projects using a folder structure. When I need to make tests I use something like the following.
.
|-- src
| |-- b.py
| `-- main.py
`-- tests
`-- test_main.py
There is just one big problem with this approach. Pytest won't run if main.py
is importing b.py
.
So far I've tried placing empty __init__.py
files inside the src
and tests
folders, both independently and together, but any of those seems to work.
It seems to me this is a pretty standard project, but I haven't been able to find a solution online. Should I use a different folder structure? Is there any recommended way to use pytest with this kind of projects?
This are the contents of the files:
# b.py
def triplicate(x):
return x * 3
# main.py
from b import triplicate
def duplicate(x):
return x * 2
# test_main.py
from src.main import duplicate
def test_duplicate():
assert duplicate(2) == 4
And this is the error I get when running pytest:
==================================================================================================== ERRORS ====================================================================================================
_____________________________________________________________________________________ ERROR collecting tests/test_main.py ______________________________________________________________________________________
ImportError while importing test module 'C:\Users\edwar\test_pytest\tests\test_main.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
c:\python39\lib\importlib\__init__.py:127: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
tests\test_main.py:1: in <module>
from src.main import duplicate
src\main.py:1: in <module>
from b import triplicate
E ModuleNotFoundError: No module named 'b'
=========================================================================================== short test summary info ============================================================================================
ERROR tests/test_main.py
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
=============================================================================================== 1 error in 0.15s ===============================================================================================
Python uses the 'environment variable' PYTHONPATH
to look for sources to import code from. By default, the directory you execute a python program is automatically included, but you want to include something like this when you test:
PYTHONPATH=$PYTHONPATH,../src python test_main.py
This is if you're executing a test from the source directory. Tools like IntelliJ (PyCharm) will let you add this as a value in your test invocation. Alternatively you can use export PYTHONPATH=...
. (Note this is for a *nix environment, your mileage on windows may vary.)
The upshot is that every directory in PYTHONPATH
will be loaded and Python will attempt to use it as a 'root' for modules you try to import. Your basic directory structure is the most idiomatic.
PYTHONPATH
correctly.PYTHONPATH
is modified and used 'under the hood'.src
directory when running pytest
tests.autoenv
(a Python library) to enable the usage of .env
files to manage this for you (at least within a virtualenv
setup - a good idea generally).setup.py
is also idiomatic for including many modules, and may provide a more convenient path for the situation you're handling.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With