Programmer Thoughts

By John Dickinson

Three tier python imports

February 28, 2009

Suppose you want to write a python module, and, like a good software developer, you want to keep a separation between your development, model/testing, and production versions of your code. This is a simple task with a few tricks in init.py.

First, our tester code:

1     import module
2     x = module.test.Klass()
3     print x.status()
4     
module/_dev/test.py is similarly simple (the model and prod versions respectively return "model" and "prod" instead of "dev"):
1     class Klass(object):
2         def status(self):
3             return '%s in dev' % str(self)

module/__init__.py:

 1     import os
 2 
 3     env = os.environ.get('ENV','dev').lower()
 4 
 5     if env == 'prod':
 6         from _prod import *
 7     elif env == 'model':
 8         from _model import *
 9     else:
10         from _dev import *

__init__.py in _dev, _model, and _prod:

 1     import os
 2 
 3     def _load_code():
 4         parent_dir = os.path.dirname(__file__)
 5         base = os.path.basename(os.path.dirname(parent_dir))
 6         modules = []
 7         for root, dirs, files in os.walk(parent_dir):
 8         for name in files:
 9             if name.endswith('.py') and \
10               not name.startswith('__') and \
11               not name.startswith('.'):
12                 module_name = '%s.%s.%s' % (base,
13                             os.path.basename(parent_dir),
14                             name.rsplit('.', 1)[0].replace(os.sep, '.'))
15                 __import__(module_name)
16                 modules.append(module_name)
17         return modules
18 
19     __all__ = []
20 
21     def update__all__():
22         global __all__
23         __all__ = [x.rsplit('.',1)[-1] for x in _load_code()]
24 
25     update__all__() # intial setup

When tester.py is run, it checks the environment variable ENV and imports the proper version of the file.

    $ ENV=dev python ./tester.py
    <module._dev.test.Klass object at 0x9d66e2c> in dev
    $ ENV=model python ./tester.py
    <module._model.test.Klass object at 0x9435e2c> in model
    $ ENV=prod python ./tester.py
    <module._prod.test.Klass object at 0x9f12e2c> in prod

Full source code.

This work is licensed under a Creative Commons Attribution 3.0 Unported License.

The thoughts expressed here are my own and do not necessarily represent those of my employer.