pytest: Module errors no matter what when running specific files or directories

Hello

I have been trying to get pytest to work for a project, but there seems to be no way of getting it to find the modules correctly when running python3 -m pytest tests/some_test.py, python3 -m pytest tests/, pytest tests/some_test.py or pytest tests/.

The structure (right now) is something like

.
├── src
│   ├── __init__.py
│   ├── conftest.py
│   ├── folders_with_source_code
│   │   ├──  __init__.py
│   │   ├── some_python_files.py
│   │   └──...
│   ...
│   ├── main.py
│   ├── models
│   │   ├── __init__.py
│   │   └── SFTPConnectionModel.py
│   └── utils
│       ├── __init__.py
│       ├── ...
│       └── constants_datalayer.py
├── tests
│   ├── __init__.py
│   ├── mocks
│   │   ├── __init__.py
│   │   ├── conftest.py
│   │   └── mock_SFTP_helper.py
│   └── test_extractors
│       ├── __init__.py
│       ├── extractor_ftp_pytest_test.py
│       └── test_extractor_ftp_nose.py (This one is commented out to avoid problems, but works with nose)
├── requirements.txt
├── README.md
├── cfg
│   └── environment_configuration.env
└── venv
    ├── bin
     ...

Where the tests/ folder is outside where our code is (src/). Nose can run this perfectly, even individual files, and the program itself runs perfectly fine, no import errors. Why then is pytest giving ModuleNotFound errors?

(venv) boscodomingo@Boscos-MacBook-Pro datalayer % python -m pytest tests/test_extractors/extractor_ftp_pytest_test.py 
================================================================================================================================================== test session starts ==================================================================================================================================================
platform darwin -- Python 3.8.10, pytest-5.4.3, py-1.10.0, pluggy-0.13.1
rootdir: /Users/boscodomingo/datalayer
collected 0 items / 1 error                                                                                                                                                                                                                                                                                             

======================================================================================================================================================== ERRORS =========================================================================================================================================================
__________________________________________________________________________________________________________________________ ERROR collecting tests/test_extractors/extractor_ftp_pytest_test.py __________________________________________________________________________________________________________________________
ImportError while importing test module '/Users/boscodomingo/datalayer/tests/test_extractors/extractor_ftp_pytest_test.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
tests/test_extractors/extractor_ftp_pytest_test.py:4: in <module>
    from src.extractors import experian_ftp
src/extractors/experian_ftp.py:6: in <module>
    from utils.constants_datalayer import (
E   ModuleNotFoundError: No module named 'utils'

I have tried all possible combinations of things: adding (and removing) __init__.py files almost everywhere, same with conftest.py, using the import-mode=append and =prepend, downgrading from 6.2.4 to 5.4.3… nothing works.

I’d love some help here, because I am exhausted at this stage and thinking of going on ahead with nose instead, but I’d rather stick to pytest since it is better maintained and generally looks like a better fit. Thank you in advance.

This has been tried in a MacBook Pro M1, in a virtual env with Python 3.8.10 (64-bit, arm64) and pytest 6.2.4

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 15 (7 by maintainers)

Most upvoted comments

Final version of the solution (works for all kinds of tests; I imagine you can pass normal arguments too and I reckon it should still work):

import sys
from os import path
from pathlib import Path

import pytest


def fix_imports_path():
    src_folder = path.join(str(Path(__file__).parent.parent.resolve()), "src")
    sys.path.insert(0, src_folder)


if __name__ == "__main__":
    fix_imports_path()
    if len(sys.argv) > 1:
        sys.exit(pytest.main(sys.argv[1:]))
    sys.exit(pytest.main())

It even works with the built-in tests in VS Code after adding /Users/boscodomingo/datalayer/src, NOT ~/datalayer/src to my PYTHONPATH via export PYTHONPATH="/Users/boscodomingo/datalayer/src:${PYTHONPATH}" in ~/.zshrc

Thank you so much for the help!!

So yours also works with a bit of modification:

from pathlib import Path
import os
import sys
import pytest
sys.path.insert(0, os.path.join(str(Path(__file__).parent.parent.resolve()), "src"))

pytest.main()
pytest.main(["tests/"])
pytest.main(["tests/test_extractors/extractor_ftp_pytest_test.py"])