RedHack
RedHack

Reputation: 285

Python3 Relative Imports inside a package

I realize that there are a lot of questions about this on StackOverflow already, but I find the solutions to be entirely unclear and often contradicting of each other.

I have the following scenario: I am writing a python (Python 3.4) package with the following structure:

mypackage/
    __init__.py (empty file)
    mydir1/
        __init__.py (empty file)
        mymodule1.py
    mydir2/
        __init__.py (empty file)
        mymodule21.py
        mymodule22.py
    mydir3/
        __init__.py (empty file)
        mymodule31.py
        mymodule32.py
    tests/
        __init__.py (empty file)
        test_something_in_mydir1.py
        test_something_in_mydir2.py
        test_something_in_mydir3.py

I want the files within the tests/ directory to contain unit tests of everything inside the package. The problem is that no matter which approach I try, I get this error:

SystemError: Parent module '' not loaded, cannot perform relative import

I should note that I want this to work "out of the box" which means that I do not want to import things using their absolute paths and I do not want to change my path variable. None of these solutions seem very pythonic and its driving me slowly up the wall. Is there really no way to do this?

I've tried a bunch of stuff already, including examples below, but they all seem to produce the same result:

from ..mydir1.mymodule1 import *
from .mypackage.mydir1.mymodule1 import *
from ...mypackage.mydir1.mymodule1 import *

And I've tried overwriting the __all__ variable in each of the __init__.py files as well as doing the imports as shown here: https://docs.python.org/3/reference/import.html#submodules

Can anyone tell me how to structure the imports (for example) in the file test_something_in_mydir1.py in such a way as to have access to all the classes/functions that are found in mymodule1.py for unit testing the package?

Upvotes: 1

Views: 574

Answers (1)

Mark Tolonen
Mark Tolonen

Reputation: 177891

If test_something_in_mydir1.py contains:

import unittest
from ..mydir1 import mymodule1

class Test1(unittest.TestCase):
    def test1(self):
        self.assertEqual(mymodule1.x,1) # mymodule1 trivially contains x=1

And if the unit tests were launched from the directory containing the package (in this case, C:\Test) using the following command:

py -m unittest discover -v

The tests are discovered and run correctly with relative imports:

C:\Test>tree /f
Folder PATH listing
Volume serial number is CE8B-D448
C:.
└───mypackage
    │   __init__.py
    │
    ├───mydir1
    │       mymodule1.py
    │       __init__.py
    │
    ├───mydir2
    │       mymodule21.py
    │       mymodule22.py
    │       __init__.py
    │
    ├───mydir3
    │       mymodule31.py
    │       mymodule32.py
    │       __init__.py
    │
    └───tests
            test_something_in_mydir1.py
            __init__.py


C:\Test>py -m unittest discover -v
test1 (mypackage.tests.test_something_in_mydir1.Test1) ... ok

----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

Upvotes: 1

Related Questions