Demo, all content is generated
Question

pytest: ModuleNotFoundError: No module named 'app' but the app runs fine

Solved · 268 views · asked by ravi_k · edited

Structure:

myproject/
  app/
    main.py
    services/pricing.py
  tests/
    test_pricing.py

uvicorn app.main:app runs fine from myproject/. But pytest from the same folder:

ImportError while importing test module 'tests/test_pricing.py'.
E   ModuleNotFoundError: No module named 'app'

ChatGPT told me to add sys.path.insert(0, ...) at the top of every test file. There has to be a better way?

What I’ve tried

The sys.path hack (works but ugly), adding init.py to tests/ (didn't help), running from inside tests/.

Comment
The sys.path thing is in half of all ChatGPT test files I've seen. Glad there's a real answer here. ines_data · edited

3 answers

Marked as helpful by the asker
marco_py · edited

uvicorn works because python -m-style startup puts the current directory on sys.path. The pytest command doesn't. Tell pytest in config:

# pyproject.toml
[tool.pytest.ini_options]
pythonpath = ["."]
testpaths = ["tests"]

Or run it as python -m pytest, which puts the cwd on the path the same way.

Delete the sys.path lines after that.

Comment
pyproject thing worked, removed the hack from 7 files. Thanks! ravi_k · edited
Short and correct. olu_backend · edited
olu_backend · edited

For a bigger project the "proper" route is to make the app an installable package ([project] table in pyproject, then pip install -e .). Then imports work the same in tests, scripts and production, no path config at all.

For this size pythonpath = ["."] is completely fine though.

Comment
grace_mw · edited

Third option you'll see in older projects: an empty conftest.py in the project root. With the default import mode pytest puts that folder on sys.path. Works, but the pyproject setting says what it does, so I'd use that.

Comment