Jon Cage
Jon Cage

Reputation: 37516

Why can't I reference a module (using a relative path) from it's unit tests?

I have a Python module I'm working on to add some unit tests.

The project layout looks something like this:

myproj\
    __init__.py
    myproj.py
    test\
        test_myproj.py

In test_myproj.py I'm trying to import the parent module as follows:

from .. import myproj

When I try and run it though, I get this:

Traceback (most recent call last):
  File "C:\Projects\myproj\test\test_myproj.py", line 6, in <module>
    from .. import myproj
SystemError: Parent module '' not loaded, cannot perform relative import

Various sources on the internet suggest this should work so what am I missing?

Upvotes: 1

Views: 199

Answers (1)

Nikita
Nikita

Reputation: 6341

You have to make your test directory a package - add __init__.py file to the test directory. After this you need your test_myproj.py file to have a __name__ of myproj.test.test_myproj when it is executed, so that it could compute the relative import path to myproj. Which will lead to from .. import myproj being interpreted as from myproj import myproj. But when you run your test file directly the __name__ is set to __main__, so it can't calculate relative import. To fix this, the test file should be imported instead of being run directly. Create a separate file (e.g. testrunner.py), which you will run to perform tests, and in that file import your test module(s) (e.g. test_myproj.py), obviously without relative import syntax or the problem will repeat. The import will lead to your test file being executed with the __name__ value, that will allow to calculate relative import. E.g.:

Add testrunner.py as shown:

testrunner.py
myproj\
    __init__.py
    myproj.py
    test\
        __init__.py
        test_myproj.py

testrunner.py content:

from myproj.test import test_myproj.py

run your test using:

python C:\Projects\testrunner.py

or

cd C:\Projects\
python testrunner.py

This way it's probably best to add another directory that will keep both testrunner.py and your myproj package.

See more thorough explanation on relative import in the answer here.

There's a note in official docs for this matter:

Note that relative imports are based on the name of the current module. Since the name of the main module is always "__main__", modules intended for use as the main module of a Python application must always use absolute imports.

Upvotes: 2

Related Questions