This problem has been eating away at me for a while. For some reason, the way I import my modules works only either for testing or for library usage. Both times the error is a Module not found error. Say I have the following Python repo:
- src
- example
- dir
- internal.py
- __init__.py
- main.py
- __init__.py
- test
- test_main.py
- __init__.py
- setup.cfg
- setup.py
Within setup.cfg
, I have:
[metadata]
name = wf
version = 1.0.0
[options]
include_package_data = True
packages = find:
[options.packages.find]
where=src
I don't want the user to import from src
, but instead import from example
. After all, nobody imports from src
, and this is the conventional structure, right?
However, now I've been encountering 2 types of errors, depending on my choice:
Choice 1
For python files in src
and test
, all imports are of the form from src.example.... import ...
. In this case, unit tests work without issues, in particular python -m unittest discover test
. However, if I create a virtual environment in a separate directory, and pip install this directory and run
# script.py
from example.main import ...
# code that calls functions in main that import from internal.py
I encounter ModuleNotFoundError: no module named 'dir'
. Only if I remove the src
from imports do I avoid this issue.
Choice 2
I'm guessing the error is because of how I defined the setup in my cfg
file, so I remove src
from src.example.... import ...
within the example directory. But now, my unit tests fail! This time, the error is ModuleNotFoundError: No module named 'dir'
.
I've looked into some other options.
- Relative imports: I've heard relative imports are fragile, so I avoid them in favor of absolute imports, which IDEs like PyCharm support very easily.
- Sys add path: I've heard that people have complained about how this is a wordy solution, and it is not agnostic, and I agree since I plan to scale up testing, so I would like to avoid it too if possible. I'm referring to this post. I'm also aware of the 'nose' suggestion underneath, but do we really need a 3rd party for this?
This has to be a commonly encountered issue... if someone knows where the fix lies, or if there is some template example Python repository which addresses these concerns, I'd be very thankful!