Reputation: 9828
I want my tests folder separate to my application code. My project structure is like so
myproject/
myproject/
myproject.py
moduleone.py
tests/
myproject_test.py
myproject.py
from moduleone import ModuleOne
class MyProject(object)
....
myproject_test.py
from myproject.myproject import MyProject
import pytest
...
I use myproject.myproject
since I use the command
python -m pytest
from the project root directory ./myproject/
However, then the imports within those modules fail with
E ModuleNotFoundError: No module named 'moduleone'
I am running Python 3.7 and have read that since 3.3, empty __init__
files are no longer needed which means my project becomes an implicit namespace package
However, I have tried adding an __init__.py
file in myproject/myproject/
and also tried adding a conftest.py
file in myproject/
but neither works
I have read answers that say to mess with the paths and then upvoted comments in other questions saying not to.
What is the correct way and what am I missing?
EDIT;
Possibly related, I used a requirements.txt
to install pytest using pip. Could this be related? And if so, what is the correct way to install pytest in this case?
EDIT 2:
One of the paths in sys.path
is /usr/src/app/
which is a docker volume lined to /my/local/path/myproject/
.
Should the volume be /my/local/path/myproject/myproject/
instead?
Upvotes: 110
Views: 114330
Reputation: 877
I didn't see quite this solution yet.
I had to add __init__.py
to both the root folder and the test folder.
Like so:
myproject/
__init__.py
myproject/
myproject.py
moduleone.py
tests/
__init__.py
myproject_test.py
Furthermore the import of the function needs to include the folder name:
from myproject.myproject import MyClass
Upvotes: 0
Reputation: 1
I noticed that the import in the myproject.py looks like this:
from moduleone import ModuleOne
try replacing the path with the full one, like
from myproject.moduleone import ModuleOne
the initial error looks logical, because there is no moduleone module in the tests directory from which the program is run
it helped in my case
Upvotes: 0
Reputation: 415
In 2023.02, according to the document of pytest, you can simply add following config to your pyproject.toml to solve this problem
[tool.pytest.ini_options]
pythonpath = "src"
addopts = [
"--import-mode=importlib",
]
Upvotes: 29
Reputation: 1696
Try adding a single __init__.py
to your tests directory (a level up from your module) with this contents:
import sys
sys.path.append('.')
sys.path.append('./my_module')
Your file structure should look like this:
project
my_module
package.py
tests
__init__.py
my_tests.py
The first append to sys.path
will enable you to import from <your-module-name>
and the second will enable your packages to import as normal.
In your tests you can import by using from my_module.package import function
whereas in your module import using simply from package import function
.
Edit: Seems like this solution is not universal (like the others).
I was able to solve this issue using help from this answer.
Add an __init__.py
to your main module directory that contains
import pathlib, sys
sys.path.append(str(pathlib.Path(__file__).parent))
I also added another __init__.py
to my tests
directory (thanks to this answer) with
import sys
sys.path.append('.')
Upvotes: 8
Reputation: 1972
For me, when I was checking my project structure I found parent directory and sub directory having same names. When I changed the directory name, I got it working. So,
# Did not work
- same_name_project/
- same_name_project/
- tests/
# Worked
- different_named_project/
- a_unique_directory/
- tests/
Upvotes: 0
Reputation: 21
I suggest you have a code structure like this:
myproject/
helpers/
moduleone.py
moduletwo.py
tests/
myproject_test.py
conftest.py
And the content of conftest.py file is:
pytest_plugins = ['helpers']
Run pytest
again.
Upvotes: 2
Reputation: 635
The simplest solution I found was to manually add my target module to syspath. Lets say you have a structure like this:
flaskapp
- src
-- app.py
-- utils
-- ...
- tests
docs
venv
This makes my test
folder a sibling to my module's src
folder. If I start putting test_*
files that need to import some of the module's code, I can simply:
import src.utils.calculator
And this would be fine until I try to import a file that imports another file from the module. The solution is simple: add a __init__.py
to your tests
folder, and put this line inside:
import sys, os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../src')))
And just modify the last part relative to your module location and folder name
Upvotes: 0
Reputation: 1
I have resolved it by adding export PYTHONPATH="your root dir/src"
i.e.
export PYTHONPATH="/builds/project/src"
poetry run pytest .....
Upvotes: 0
Reputation: 2243
I was facing the issue which i resolved by
pytest
at the root of my project using pip install pytest
__init__.py
in the sibling of my test_file.py
which i wanted to execute.Upvotes: 0
Reputation: 1674
In my case it is because I installed pytest
on the system level but not in my virtual environment.
You can test this by python -m pytest
. If you see ModuleNotFoundError: No module named 'pytest'
then your pytest
is at the system level.
Install pytest
when the virtual environment is activated will fix this.
Upvotes: 11
Reputation: 1330
Using poetry and pytest 5.4.3, I had the following structure (some folders / files have been removed for clarity):
.
├── my_app
│ ├── __init__.py
│ ├── main.py
│ ├── model.py
│ └── orm.py
├── poetry.lock
├── pyproject.toml
├── README.rst
└── tests
├── __init__.py
├── conftest.py
├── test_my_app.py
└── utilities
└── db_postgresql_inmemory.py
pytest_plugins = [
"utilities.db_postgresql_inmemory",
]
which generated a module not found error for the fixture:
ImportError: Error importing plugin "utilities.db_postgresql_inmemory": No module named 'utilities'
None of the other answers have worked for me, as I have tried to add:
[me@linux ~/code/my_app]touch tests/utilities/__init__.py
[me@linux ~/code/my_app]touch ./test_blank.py
I could make the import from conftest.py work by REMOVING both __init__.py
files:
[me@linux ~/code/my_app]rm tests/utilities/__init__.py tests/__init__.py
Upvotes: 1
Reputation: 1091
PYTHONPATH
env. varPYTHONPATH=. pytest
As mentioned by @J_H, you need to explicitly add the root directory of your project, since pytest
only adds to sys.path
directories where test files are (which is why @Mak2006's answer worked.)
If you do not want to type that long command all the time, one option is to create a Makefile
in your project's root dir with, e.g., the following:
.PHONY: test
test:
PYTHONPATH=. pytest
Which allows you to simply run:
make test
Another common alternative is to use some standard testing tool, such as tox.
Upvotes: 71
Reputation: 2855
In my case I added a __init__.py
to my test directory with this inside it:
import sys
sys.path.append('.')
My app code is at the same level as my test directory.
Upvotes: 19
Reputation: 20415
Be sure to include .
dot in the $PYTHONPATH
env var.
Use $ python -m site
, or this code fragment to debug such issues:
import pprint
import sys
pprint.pprint(sys.path)
Your question managed to use myproject
at three different levels. At least during debugging you might want to use three distinct names, to reduce possible confusion.
Upvotes: 21
Reputation: 42886
Not sure if this solution was specific to my problem, but I simply add __init__.py
to my tests
folder and that solved the problem.
Upvotes: 104
Reputation: 171
Kept everything same and just added a blank test file at the root folder .. Solved
Here are the findings, this problem really bugged me for a while. My folder structure was
mathapp/
- server.py
- configuration.py
- __init__.py
- static/
- home.html
tests/
- functional
- test_errors.py
- unit
- test_add.py
and pytest would complain with the ModuleNotFoundError.
I introduced a mock test file at the same level as mathsapp and tests directory. The file contained nothing. Now pytest does not complain.
Result without the file
$ pytest
============================= test session starts =============================
platform win32 -- Python 3.8.2, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: C:\mak2006\workspace\0github\python-rest-app-cont
collected 1 item / 1 error
=================================== ERRORS ====================================
_______________ ERROR collecting tests/functional/test_func.py ________________
ImportError while importing test module 'C:\mainak\workspace\0github\python-rest-app-cont\tests\functional\test_func.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
tests\functional\test_func.py:4: in <module>
from mathapp.service import sum
E ModuleNotFoundError: No module named 'mathapp'
=========================== short test summary info ===========================
ERROR tests/functional/test_func.py
!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!
============================== 1 error in 0.24s ===============================
Results with the file
$ pytest
============================= test session starts =============================
platform win32 -- Python 3.8.2, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: C:\mak2006\workspace\0github\python-rest-app-cont
collected 2 items
tests\functional\test_func.py . [ 50%]
tests\unit\test_unit.py . [100%]
============================== 2 passed in 0.11s ==============================
Upvotes: 5
Reputation: 1618
I ran into this issue as well and am using poetry for dependency management and direnv for my project specific environment variables. Please note, I am relatively new to Python so I don't know if this is the correct fix.
Here is my entire .envrc file:
layout_poetry() {
if [[ ! -f pyproject.toml ]]; then
log_error 'No pyproject.toml found. Use `poetry new` or `poetry init` to create one first.'
exit 2
fi
local VENV=$(poetry env list --full-path | cut -d' ' -f1)
if [[ -z $VENV || ! -d $VENV/bin ]]; then
log_error 'No created poetry virtual environment found. Use `poetry install` to create one first.'
exit 2
fi
VENV=$VENV/bin
export VIRTUAL_ENV=$(echo "$VENV" | rev | cut -d'/' -f2- | rev)
export POETRY_ACTIVE=1
PATH_add "$VENV"
}
layout poetry
export PYTHONDONTWRITEBYTECODE=1
export PYTHONPATH="$PWD/project_name"
I don't know if I need to layout poetry because it is supposed to be creating virtual environments for us already but this is what I coworker recommended so I went with it. Layout poetry also didn't work without that function and it didn't like when I added it to my zshenv so I added it here.
For this specific question, the last line is the money maker.
Upvotes: 0
Reputation: 9828
So it seems that the sys.path
has to include the application directory rather than the project root folder containing the application directory and test directory.
So in my case /my/local/path/myproject/myproject/
had to be in sys.path
rather than /my/local/path/myproject/
.
Then I could run pytest
in /my/local/path/myproject/
(didn't need python -m pytest
). This meant that the modules within /myproject/myproject/
could find each other and the tests as well without any namespace nesting.
So my tests looked like
from moduleone import ModuleOne
import pytest
def test_fun():
assert ModuleOne.example_func() == True
That said, there seem to be many gotchas, so I have no idea if this is correct..
Upvotes: 2