I have an application with a heirarchy of packages. There are a fair number of modules that reference other modules higher up in the package heirarchy. As exemplified below, I can use relative imports to solve this problem. However, running the module directly for testing fails with an Attempted relative import in non-package
exception.
Is there a better way to organize my application or my import statements so that modules can both be executed individually for testing and imported from other modules?
Example
\spam
\morespam
child.py
base.py
\eggs
user.py
base.py
class Base(object):
def hello(self):
print 'Um, wot?'
child.py
from ..base import Base # references the parent package correctly,
# but fails when this module is executed individually
class Child(Base):
def hello(self):
print 'Hello, world!'
if __name__ == '__main__':
import unittest
# ... unit test code ...
user.py
from spam.morespam.child import Child
print Child().hello()
Existing solution
I've found that I can add the following header added to the top of a module that needs to reference modules higher in the hierarchy:
if __name__ == '__main__':
import sys, os
sys.path.append(os.path.abspath(os.path.join(sys.path[0], '..')))
The downside is that I need to add this code all over the place, and it isn't constant: the '..'
relative path varies based on the depth of the package in the hierarchy.
Other possible solutions...
- I could create a .pth file with my application root. Unfortunately, this must be added to the site-packages folder of my Python installation, so it's not very application-specific.
- I could temporarily add my application root to the PYTHONPATH, and make all my modules reference packages from the root. This eliminates the simplicity of running a script by simply calling
python.exe whatever.py
, though. - I could write some sort of module that, when imported, would look for a marker file in the root folder of my application. This generic module could then be installed to my local Python installation and imported by every module in my app, thus guaranteeing that the root is in PYTHONPATH, regardless of which module I'm executing.