1

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?

Jon Cage
  • 36,366
  • 38
  • 137
  • 215
  • May be related question has an answer for you? http://stackoverflow.com/questions/16981921/relative-imports-in-python-3 – jamesc Mar 24 '16 at 12:35

1 Answers1

2

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.

Community
  • 1
  • 1
Nikita
  • 6,101
  • 2
  • 26
  • 44
  • How do you "set `__name__` of` myproj.test.test_myproj`"? – Jon Cage Mar 24 '16 at 14:24
  • You don't set it, it's set automatically by Python, you can only read it. Please, see the link with example including the code in the end of my answer. You can see it yourself, just add `print(__name__)` to the module you wish to check and see the output, when you execute it and when you import it. – Nikita Mar 24 '16 at 15:25
  • I've read it but it looks like you're saying the answer is that it's impossible to have the unit tests as a subdirectory; they must be sat at a level parallel to myproj? – Jon Cage Mar 24 '16 at 15:32
  • Okay, I understand now. How would you handle the situation where I have lots of packages under `C:\Projects\`? Presumably I'd have to make one test runner per package (to enable them to be run independently? – Jon Cage Mar 24 '16 at 15:38
  • That's why I wrote: "This way it's probably best to add another directory that will keep both testrunner.py and your myproj package." :) . So that the structure is: `C:\Projects\project_1_folder\[docs, testrunner.py, myproj_package[__init__.py, etc.]], C:\Projects\project_2_folder\[docs, testrunner.py, mysuperproj_package[__init__.py, etc.]]`. – Nikita Mar 24 '16 at 15:42
  • If you do that though, don't relative imports actually work properly at that point (i.e. testrunner is nolonger required)? – Jon Cage Mar 24 '16 at 15:54
  • What do you mean "work this way", you mean running `python C:\Projects\myproj\test\test_myproj.py`? This way `__name__='__main__'` anyway and relative imports in `test_myproj.py` won't resolve. May be there's a better way, but I don't know it. So if you find one, please, share. There are other test-runners with auto test discovery and etc, but they will import your package anyway to run tests, so basicly you do the same thing in your `testrunner.py`. – Nikita Mar 24 '16 at 16:00