ModuleNotFoundError with pytest

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?

  • 1

    Honestly, this is going to be a opinion war if anything. You could move the test folder into your main structure and execute it from there, and your could would work as-is. Wouldn’t need to change a thing since the import paths would be relevant. Other than that, you would need to monkey-patch the path in the test-files to include the target directory, and it wouldn’t be a bad thing (opinion). Just know why and what you’re doing.

    – 

  • 2

    Long comments.. You could also (on your command line) append the PYTHONPATH to include the target directory. Meaning you wouldn’t have to manipulate sys.path from any of your scripts, but you would get a updated path upon running the test. PYTHONPATH=./myproject python -m pytest as if you did.

    – 




  • Of the directories you listed in the project structure, which (if any) are in your PYTHONPATH?

    – 

  • @JohnGordon updated the question with new info

    – 

  • 1

    have you tried adding the empty init.py to the ./tests directory instead of your project directory. It might sound strange, but worth trying.

    – 

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.

Solution: use the PYTHONPATH env. var

PYTHONPATH=. 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.)


Good practice: use a Makefile or some other automation tool

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.

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.

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.

Leave a Comment