0

I have a test that passes with pytest. I also have an adjacent source that's a console app (not pytest) that exercises the same function that barfs with ModuleNotFoundError for the same function call.

mylib/mylib.py:

def adder(num1, num2): return num1 + num2 

test/my_test.py:

from mylib.mylib import adder def test_adder(): assert adder(2, 2) == 4 

test/mytest_outside_pytest.py:

from mylib.mylib import adder print(str(adder(2, 2))) 

As I suggest pytest completes and indicates the test passed, but the following does not:

$ python3 test/mytest_outside_pytest.py Traceback (most recent call last): File "test/mytest_outside_pytest.py", line 1, in <module> from mylib.mylib import adder ModuleNotFoundError: No module named 'mylib' 

Nor does:

$ cd test/ $ python3 mytest_outside_pytest.py Traceback (most recent call last): File "mytest_outside_pytest.py", line 1, in <module> from mylib.mylib import adder ModuleNotFoundError: No module named 'mylib' 

I have empty __init__.py in both folders. I don't know what pytest does to path loading that I can't replicate in my "main" console app. Of course I don't really care about an adder lib, I'm just aiming at the smallest reproducible problem.

3
  • If you call python3 -m pytest ..., it adds the current path to the Python path, so the modules will be found. Just calling python3 test/mytest.py does not do this. As the import is relative to that root dir, the root dir must be in the Python path for the import to work. Commented Sep 24, 2020 at 10:51
  • I just tried python3 -m pytest test/mytest_outside_pytest.py and it says "collected 0 items" so not quite the outcome I was looking for .. "4" in stdout. Commented Sep 24, 2020 at 12:14
  • I've bolded the file names in the post. See mytest_outside_pytest.py - third code block Commented Sep 24, 2020 at 13:32

1 Answer 1

2

pytest has a quite complex mechanism to add some directories to the PYTHONPATH and allow tests to run automagically (see the doc)

When you do not use pytest you do not have this mechanism and you have to manage the PYTHONPATH by yourself.


Why the PYTHONPATH is not correct in your case?

When you run a module using python path/to/module.py, the interpreter adds the directory containing the module (absolute path of path/to in this example) in the PYTHONPATH.

In your case, you run python test/mytest_outside_pytest.pyand the interpreter adds the absolute path of test directory in the PYTHONPATH.

You can check it by adding import pdb; pdb.set_trace() at the very beginning of your mytest_outside_pytest.py module to enter a debug session and run it. Then import sys and display the sys.path to see that test is the first directory in your PYTHONPATH.

You can also see that the root directory is not listed and thus the packages it contains cannot be imported.


How to solve it?

It can be done in multiple ways.

You can manually define the PYTHONPATH in your command:

PYTHONPATH=. python test/mytest_outside_pytest.py 

or you can use python -m ... as suggested in comment (do not forget that in this case, you have to specify a module, not a path, and remember that it will work only from the directory containng the mylib and test packages):

python -m test.mytest_outside_pytest 

In both cases, a debug session can show you that the root directory and the test directory are in the PYTHONPATH

Sign up to request clarification or add additional context in comments.

1 Comment

python3 -m test.mytest_outside_pytest does indeed simply invoke the non-test in test/ and produce the desired output, "4" (without pythonpath changes)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.