125

I have a folder structure like this

App
--App
  --app.py       
--Docs
--Tests
  --test_app.py

In my test_app.py file, I have a line to import my app module. When I run py.test on the root folder, I get this error about no module named app. How should I configure this?

zsljulius
  • 3,813
  • 8
  • 36
  • 61
  • 1
    Possible duplicate of [PATH issue with pytest 'ImportError: No module named YadaYadaYada'](https://stackoverflow.com/questions/10253826/path-issue-with-pytest-importerror-no-module-named-yadayadayada) – hoefling Aug 15 '18 at 11:37

14 Answers14

191

Working with Python 3 and getting the same error on a similar project layout, I solved it by adding an __init__ file to my tests module.

$ touch tests/__init__.py

I'm not great at packaging and importing, but I think that this helps pytest work out where the target App module is located.

jamesc
  • 5,852
  • 3
  • 32
  • 42
  • 8
    Before using this strategy, you should check the implications against pytest's best practices: https://docs.pytest.org/en/latest/goodpractices.html#choosing-a-test-layout-import-rules – jamesc Sep 16 '18 at 14:27
  • 5
    This is the only way I could make it work in Python 3. – jadianes Jan 24 '19 at 11:38
  • 23
    @jamesc I am following their "best practice" of the "outside app code" pattern and it works if I execute `coverage run -m pytest` or `python -m pytest` but fails if I run `pytest` directly with failed to load module errors. – Maximilian Burszley Oct 29 '19 at 15:12
  • 1
    @TheIncorrigible1 Really glad to see your comment here as I was stumped for a moment. I'm unsure if this is the same issue, but I've commented on GitHub: https://github.com/pytest-dev/pytest/issues/6370#issuecomment-575423003 – blong Jan 17 '20 at 01:24
  • 2
    @blong I've since resolved the problem I was running into by installing my source as a package into the virtual environment which required a deep foray into python packaging and distutils/setuptools. – Maximilian Burszley Jan 17 '20 at 01:39
  • confirm_ this works only as @burszely suggested – gdm Sep 23 '22 at 10:58
98

I already had an __init__.py file in the /App/App directory and wanted to run tests from the project root without any path-mangling magic:

 python -m pytest tests

The output immediately looks like this:

➟  python -m pytest tests
====================================== test session starts ======================================
platform linux -- Python 3.5.1, pytest-2.9.0, py-1.4.31, pluggy-0.3.1
rootdir: /home/andrew/code/app, inifile: 
plugins: teamcity-messages-1.17
collected 46 items 

... lines omitted ...

============================= 44 passed, 2 skipped in 1.61 seconds ==============================
berezovskyi
  • 3,133
  • 2
  • 25
  • 30
  • 7
    Were you able to figure out the reason why launching `py.test` directly fails to discover the `/App/App`? – rr- Apr 02 '16 at 11:25
  • 3
    well python does add the current directory to the pythonpath, so you are still using path-mangling magic, btw that's why it works! – Danny Jun 06 '16 at 15:01
37

I had a similar problem and had to delete __init__.py from the root and add an __init__.py to the tests folder.

Asclepius
  • 57,944
  • 17
  • 167
  • 143
Tiago De Souza
  • 471
  • 5
  • 4
33

Running pytest with the python -m pytest command helps with this exact thing.

Since your current package is not yet in your $PYTHONPATH or sys.path - pytest gets this error.

By using python -m pytest you automatically add the working directory into sys.path for running pytest. Their documentation also mentions:

This is almost equivalent to invoking the command line script pytest

nchopra
  • 511
  • 4
  • 9
  • 2
    the best answer for python 3.8 – JP Siyyadri Jan 20 '23 at 12:10
  • 1
    It is the same for me. I had __init__.py but it still did not work. While I found out `python -m pytest .` works, I could not figure it out why `pytest . ` does not work. Thanks for a good and brief explanation. – Karimai Aug 07 '23 at 10:54
29

So you are running py.test from /App. Are you sure /App/App is in your $PYTHONPATH?

If it's not, code that tries to import app will fail with such a message.

EDIT0: including the info from my comment below, for completeness.

An attempt to import app will only succeed if it was executed inside /App/App, which is not the case here. You probably want to make /App/App a package by putting __init__.py inside it, and change your import to qualify app as from App import app.

EDIT1: by request, adding further explanation from my second comment below.

By putting __init__.py inside /App/App, that directory becomes a package. Which means you can import from it, as long as it - the directory - is visible in the $PYTHONPATH. I.e. you can do from App import app if /App is in the $PYTHONPATH. Your current working directory gets automatically added to $PYTHONPATH, so when you run a script from /App, the import will work.

Dun Peal
  • 16,679
  • 11
  • 33
  • 46
  • 1
    I have run `pip install -e .` on `/App`, so the package is installed to the `/usr/local` library. I would think this adds my folder to the path? – zsljulius Jan 08 '14 at 01:08
  • 2
    There's no reason for `/App/App` to automatically be added into the `$PYTHONPATH`, regardless of where you installed `pip`. An attempt to `import app` will only succeed if it was executed *inside* `/App/App`, which is not the case here. You probably want to make `/App/App` a package by putting `__init__.py` inside it, and change your import to qualify `app` as `from App import app`. – Dun Peal Jan 08 '14 at 01:11
  • 1
    My test can be ran now. I am still confused about the $PYTHONPATH part. Is it that if I add __init__.py to my `/App/App` folder, python will automatically insert the `/App/App` folder into the path? – zsljulius Jan 09 '14 at 13:49
  • 3
    @zsljulius: by putting `__init__.py` inside `/App/App`, that directory becomes a package. Which means you can import from it, as long as it - the directory - is visible in the `$PYTHONPATH`. I.e. you can do `from App import app` if `/App` is in the `$PYTHONPATH`. Your current working directory gets automatically added to `$PYTHONPATH`, so when you run a script from `/App`, the import will work. – Dun Peal Jan 10 '14 at 10:15
12

I also got same error while running test cases for my app located as below

myproject
  --app1
    --__init.py__
    --test.py
  --app2
    --__init.py__
    --test.py
  --__init.py__

I deleted my myproject's init.py file to run my test cases.

Jay
  • 329
  • 2
  • 12
6

TL;DR

You might as well add an empty conftest.py file to your root app folder.

(if you take a look at the question folder structure, that would be the same level as the "Tests" folder, not inside of it).

More info:

Pytest looks for conftest.py files inside all your project folders.

conftest.py provides configuration for the file tree pytest finds it in. Because pytest somehow scans all subdirectories starting from conftest.py folder, it should find packages/modules outside the tests folder (as long as a conftest.py file is in your app root folder).

Eventually, you might want to write some code in your empty conftest.py, specially to share fixtures among different tests files, in order to avoid duplicate code. Afterall, the DRY principle (Don't Repeat Yourself) should also be follwed when writing tests.

Adding __init.py__ to the tests folder also should help pytest to find modules throughout your application. However, note that Python 3.3+ has implicit namespace packages that allow it to create a packages without an __init__.py file. That been said, creating __init__.py files for this specific purpose seems more like a a workaround for pytest than a python requirement. More about that in: Is __init__.py not required for packages in Python 3.3+

Sverissimo
  • 276
  • 4
  • 8
  • Adding `conftest.py` to the root folder helped. root units_under_tests tests conftest.py Without conftest.py in the place got the error when running pytest from the command line. – Karlis Fersters May 24 '22 at 15:32
2

I got the similar issue. And after trying multiple things including installing pytest on virtual environment and adding/removing __init__.py file from the package, none worked for me.

Solution that worked for me is(windows solution): Added Project folder(not package folder) to python path(set PYTHONPATH=%PYTHONPATH%;%CD%)

Ran my script from Project Folder and boom, it worked.

Asclepius
  • 57,944
  • 17
  • 167
  • 143
1

What worked for me: I had to make absolute imports in my test file and call python -m test in the root folder.

Luis Felipe
  • 148
  • 9
1

I hit the same issue.

my-app
--conf
--my-app
--tests

I set the __init__.py files. I added a conftest.py ( for sharing pytest.fixtures ). I added this to my Poetry file ( pyproject.toml:

[tool.pytest.ini_options]
pythonpath = [
  "."

Turned out it was my use of hyphens and not underscores ! Noo...

# pytest can't find Module
--my-app

# works
--my_app
rustyMagnet
  • 3,479
  • 1
  • 31
  • 41
1

I have the following project structure

myproject
      manage.py
      pyproject.toml
      --apps
        --app1
        --app2
      --tests
        --apps
          -- app1
          -- app2
      --config
         --settings
            base.py
            local.py

Adding init.py did not help. I was able to solve the issue by adding the following to pyproject.toml

[tool.pytest.ini_options]
DJANGO_SETTINGS_MODULE = "config.settings.local" 
Bekzod
  • 11
  • 2
1

Solution is very simple: set PYTHONPATH environment variable to . (current directory).

# Windows
set PYTHONPATH=.

# Linux 
export PYTHONPATH=.
0

Make sure you do not have an __init__(self) method in your testcase.

WestCoastProjects
  • 58,982
  • 91
  • 316
  • 560
-2

This worked for me: Went to parent app, and pip install -e . (install a local and editable app).

Yishai Landau
  • 620
  • 4
  • 14