1

Given the directory structure:

/home/user/python/mypacakge/src/foo.py
/home/user/python/mypacakge/tests
/home/user/python/mypacakge/tests/fixtures
/home/user/python/mypacakge/tests/fixtures/config.json.sample
/home/user/python/mypacakge/tests/foo_tests.py
/home/user/python/mypacakge/README.md

Where src contains the source code, and test contains the unit tests, how do I setup a "package" so that my relative imports that are used in the unit tests located in test/ can load classes in src/?

Similar questions: Python Relative Imports and Packages and Python: relative imports without packages or modules, but the first doesn't really answer my question (or I don't understand it) and the second relies on symlinks to hack it together (respectively).

Community
  • 1
  • 1
DrDamnit
  • 4,736
  • 4
  • 23
  • 38
  • You mean simply import a file like this: `from .. import src.module` ? Any class in module is then loaded.. – nir0s Mar 08 '17 at 18:26
  • Can also do `from ..src import module.class` btw – nir0s Mar 08 '17 at 18:27
  • a) it appears to not be a best practice to use relative imports, b) I get this: ValueError: Attempted relative import beyond toplevel package – DrDamnit Mar 08 '17 at 18:36
  • If you set a structure where you try to import from `repo_root/test` something in `repo_root/src`, `from .. import` will work. If you got a warning about a top level package that probably means that's not the structure of your repo. Regardless of that, Python imports packages that are part of the main package stated in setup.py. If you don't install the package, it's not available. I don't see how relative imports in tests are bad practice. Moreover, I don't even know of another way to do that that isn't ugly. – nir0s Mar 08 '17 at 18:42

1 Answers1

1

I figured it out.

You have to have __init__.py in each of the folders like so:

/home/user/python/mypackage/src/__init__.py
/home/user/python/mypackage/src/Foo.py
/home/user/python/mypackage/tests
/home/user/python/mypackage/tests/fixtures
/home/user/python/mypackage/tests/fixtures/config.json.sample
/home/user/python/mypackage/tests/foo_test.py
/home/user/python/mypackage/tests/__init__.py
/home/user/python/mypackage/README.md
/home/user/python/mypackage/__init__.py

This tells python that we have "a package" in each of the directories including the top level directory. So, at this point, I have the following packages:

mypackage
mypackage.test
mypackage.src

So, because python will only go "down into" directories, we have to execute the unit tests from the root of the top-most package, which in this case is:

/home/user/python/mypackage/

So, from here, I can execute python and tell it to execute the unittest module and then specify which tests I want it to perform by specifying the module using the command line options

python -m unittest tests.foo_test.TestFoo

This tells python:

  1. Execute python and load the module unittest
  2. Tell unit test to run the tests contained in the class TestFoo, which is in the file foo_test.py, which is in the test directory.

Python is able to find it because __init__.py in each of these directories promotes them to a package that python and unittest can work with.

Lastly, foo_test.py must contain an import statement like:

from src import Foo

Because we are executing from the top level directory, AND we have packages setup for each of the subdirectories, the src package is available in the namespace, and can be loaded by a test.

Dan D.
  • 73,243
  • 15
  • 104
  • 123
DrDamnit
  • 4,736
  • 4
  • 23
  • 38