0

I am so confused

I have a file /app/bar.py

val = 5

and a file /app/test/test_foo.py

def test_false():
    import os
    print(f'dir: {os.getcwd()}')
    from bar import val
    assert val == 5

When I run pytest from the app directory I get an error that this module cannot be resolved

/app# pytest
============================= test session starts ==============================
platform linux -- Python 3.7.4, pytest-5.0.1, py-1.8.0, pluggy-0.12.0
rootdir: /app
collected 1 item                                                               

test/test_foo.py F                                                       [100%]

=================================== FAILURES ===================================
__________________________________ test_false __________________________________

    def test_false():
        import os
        print(f'dir: {os.getcwd()}')
>       from bar import val
E       ModuleNotFoundError: No module named 'bar'

test/test_foo.py:4: ModuleNotFoundError
----------------------------- Captured stdout call -----------------------------
dir: /app
=========================== 1 failed in 0.27 seconds ===========================

I can swear I've done this before but I know that I struggle with what the root for module resolution is every darn time.

What are the actual rules on this? How am I supposed to reference the module bar so that I can import it into my test?

Edit: I have learned that the locations searched are those in sys.path. In my case that includes the /app/test directory and a bunch of others but not /app which I think makes this explicitly a pytest question - why on earth is /app not in that list if its the current directory?

George Mauer
  • 117,483
  • 131
  • 382
  • 612
  • Put an empty `conftest.py` file into `app/` if you want to run `pytest ...`, otherwise either adapt `PYTHONPATH`, or run `python -m pytest ...`. In order to be able to `import bar`, the parent dir containing `bar.py` must be in `sys.path`, no matter what way you choose to put it in there. – hoefling Aug 17 '19 at 09:01
  • 1
    `python -m pytest` is not the same as calling `pytest`; the one is python-specific "find a module named `pytest.py` in `sys.path` and execute it", the other is "run an arbitrary executable file names `pytest`". They aren't even the same files being executed. `python -m` adds `pwd` to `sys.path`, while an arbitrary executable doesn't. Also, see [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 17 '19 at 09:02

1 Answers1

1

pytest looks at following locations to locate imports:

  1. PYTHONPATH environment variable - this environment variable you can set to the path where you have the target files.
  2. The libraries directory where libraries are installed
  3. The home directory of the program. This is the path from where pytest runs (installation directory) and not the directory from where you are running your test.
  4. sys.path: Add the required directories to sys.path using sys.path.append() or sys.path.insert().

If you want to implicitly include the current directory then run the test as python -m pytest abc.py instead of pytest abc.py

fiveelements
  • 3,649
  • 1
  • 17
  • 16
  • Ah interesting, `python -m pytest` did indeed make it work - so what is the difference with that versus `pytest`? Why does the latter not include the directory it is being run from even though `os.getcwd()` returns it? – George Mauer Aug 16 '19 at 17:13