Skip to content

Instantly share code, notes, and snippets.

@paddymul
Created March 17, 2012 13:32
Show Gist options
  • Save paddymul/2059055 to your computer and use it in GitHub Desktop.
Save paddymul/2059055 to your computer and use it in GitHub Desktop.
Python relative imports

How to use python relative imports

Don’t. They are tempting, but they are a really big mess. Let’s start by figuring out what you’re really trying to accomplish. Let’s start with a directory structure.

/Grand-
       
       Tophat -
              settings.py
              global_entry_point.py
              package_1- 
                         module_1_foo.py
                         module_1_bar.py
              package_2- 
                         module_2_bof.py
                         module_2_baz.py
       
       
       Other_project-
                     random_module.py

The most common reason for wanting relative imports is so that you can run python Tophat/package_2/module_2_bof.py from anywhere on your filesystem. If module_2_bof.py is self contained, this will work, but if package_2/module_2_bof.py depends on package_1/module_1_foo.py you have a problem. This is where you would want to have a relative import, in package_2/module_2_bof.py, an import like this:

from ..package_1.module_1_foo import key_function

There are ways to do this in python, but they are more trouble than they are worth.

What you want to do is control your PYTHONPATH variable, and add Tophat to it. Then you can always do absolute imports relative to Tophat. You can add the following line to your .bashrc to accomplish this.

PYTHONPATH=$PYTHONPATH:/Grand/Tophat

But editing my .bashrc is yucky, what about virtualenv

Ahh, glad you asked. Here is the command you want to run:

cd /Grand/Tophat
add2virtualenv `pwd`

The add2virtualenv command adds a directory to a given virtualenv’s PYTHONPATH. From now on, every time you workon that virtualenv, the Tophat dir will be in your PYTHONPATH and you won’t have to worry about relative imports.

What are other common solutions to this problem?

Most projects move towards having a global_entry_point.py file that gets the path setup properly. In django this is manage.py . To add the equivalent of globally available scripts to django, you add management commands, you can then run by python django_root/manage.py my_command. This works well for django management commands which come in separate apps and can’t assume anything about your environment. The global entry point approach also has the advantage of a strict order of operations, ensuring things like the ORM are properly setup. They have the downside of tying you tightly to whatever framework you are using, remaining framework agnostic can be an uphill battle and you should decide what the best fit for you is.

Distutils uses scripts, this is fine for site-packages installed projects, but awkward for scripts that you want to develop on.

But I really really want to use relative imports.

Ok, there’s your foot, here’s your shotgun. The best system for relative imports that I have seen is Rocky Bernstein’s pyimport-relative library. This library needs to be globally installed though, so you’ll run into a bit of a chicken and egg situation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment