vastlysuperiorman vastlysuperiorman - 1 year ago 96
Python Question

More elegant solution for python imports across app/tests?

I'm trying to keep my code reasonably organized by putting tests in a separate directory from my app. However, imports work either for the app or for the tests, but not both. Here's a contrived example that illustrates my current problem:


Contents of files as follows:

import settings
from moods import Moods

words = Moods(settings.EXAMPLE)

EXAMPLE = "Wow$ Python$"
DELIM = "$"

import settings

class Moods:
def __init__(self, text):
self.text = text

def excited(self):
return self.text.replace(settings.DELIM, "!!!")

import sys, os, unittest
sys.path.insert(0, os.path.abspath('..'))

from app.moods import Moods

class TestMood(unittest.TestCase):
def setUp(self):
self.words = Moods("Broken imports$ So sad$")

def test_mood(self):
self.assertEqual(self.words.excited(), "Broken imports!!! So sad!!!")
with self.assertRaises(AttributeError):

if __name__ == "__main__":

In the current state, from
I can run the following successfully:

>> python3 app/
Wow!!! Python!!!

But when I try to run tests, the import fails in

>> python3 -m unittest discover test/
ImportError: Failed to import test module: test_moods
[ stack trace here pointing to first line of ]
ImportError: No module named 'settings'

If I modify line 1 of to read
from app import settings
, the test will pass, but normal execution of the app fails because it sees no module

The only solutions I can think of are

  1. Putting the tests in the same directory as the code (which I was trying to avoid)

  2. Adding the
    sys.path.insert(0, os.path.abspath('..'))
    to each file in my app to make the imports work the same as the test ones do (which seems messy)

Is there are more elegant way to solve this import problem?

Answer Source

You should have both app and test directory in PYTHONPATH.

One way is to replace this:

sys.path.insert(0, os.path.abspath('..'))

from app.moods import Moods

with this:

sys.path.insert(0, os.path.abspath('../app'))

from moods import Moods

Or you can set the PYTHONPATH environament variable before running the tests.

Why? Because when you run, then app is in the path, not app/.., so you want ot have the same when running tests.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download