script - How to do relative imports in Python?
relative import python (11)
"Guido views running scripts within a package as an anti-pattern" (rejected PEP-3122)
I have spent so much time trying to find a solution, reading related posts here on Stack Overflow and saying to myself "there must be a better way!". Looks like there is not.
Imagine this directory structure:
app/ __init__.py sub1/ __init__.py mod1.py sub2/ __init__.py mod2.py
mod1, and I need to import something from
mod2. How should I do it?
from ..sub2 import mod2 but I'm getting an "Attempted relative import in non-package".
I googled around but found only "
sys.path manipulation" hacks. Isn't there a clean way?
Edit: all my
__init__.py's are currently empty
Edit2: I'm trying to do this because sub2 contains classes that are shared across sub packages (
Edit3: The behaviour I'm looking for is the same as described in PEP 366 (thanks John B)
As @EvgeniSergeev says in the comments to the OP, you can import code from a
.py file at an arbitrary location with:
import imp foo = imp.load_source('module.name', '/path/to/file.py') foo.MyClass()
This is taken from this SO answer.
From Python doc,
In Python 2.5, you can switch import‘s behaviour to absolute imports using a
from __future__ import absolute_importdirective. This absolute- import behaviour will become the default in a future version (probably Python 2.7). Once absolute imports are the default,
import stringwill always find the standard library’s version. It’s suggested that users should begin using absolute imports as much as possible, so it’s preferable to begin writing
from pkg import stringin your code
Here is the solution which works for me:
I do the relative imports as
from ..sub2 import mod2
and then, if I want to run
mod1.py then I go to the parent directory of
app and run the module using the python -m switch as
python -m app.sub1.mod1.
The real reason why this problem occurs with relative imports, is that relative imports works by taking the
__name__ property of the module. If the module is being directly run, then
__name__ is set to
__main__ and it doesn't contain any information about package structure. And, thats why python complains about the
relative import in non-package error.
So, by using the -m switch you provide the package structure information to python, through which it can resolve the relative imports successfully.
I have encountered this problem many times while doing relative imports. And, after reading all the previous answers, I was still not able to figure out how to solve it, in a clean way, without needing to put boilerplate code in all files. (Though some of the comments were really helpful, thanks to @ncoghlan and @XiongChiamiov)
Hope this helps someone who is fighting with relative imports problem, because going through PEP is really not fun.
I think that what you have to ask yourself is:
- Why i need to do this?
- Is my package separation well done?
I don't know the context why you want to do it this way. But for me a cleaner design would be to have the following packages structure:
app/ __init__.py sub1/ __init__.py mod1.py sub12/ __init__.py mod2.py
Then you only have to do:
from sub12 import mod2
Let me just put this here for my own reference. I know that it is not good Python code, but I needed a script for a project I was working on and I wanted to put the script in a
import os.path import sys sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
Suppose you run at the top level, then in
from ..sub2 import mod2
Take a look at http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports. You could do
from .mod1 import stuff
This is unfortunately a sys.path hack, but it works quite well.
I encountered this problem with another layer: I already had a module of the specified name, but it was the wrong module.
what I wanted to do was the following (the module I was working from was module3):
mymodule\ __init__.py mymodule1\ __init__.py mymodule1_1 mymodule2\ __init__.py mymodule2_1 import mymodule.mymodule1.mymodule1_1
Note that I have already installed mymodule, but in my installation I do not have "mymodule1"
and I would get an ImportError because it was trying to import from my installed modules.
I tried to do a sys.path.append, and that didn't work. What did work was a sys.path.insert
if __name__ == '__main__': sys.path.insert(0, '../..')
So kind of a hack, but got it all to work! So keep in mind, if you want your decision to override other paths then you need to use sys.path.insert(0, pathname) to get it to work! This was a very frustrating sticking point for me, allot of people say to use the "append" function to sys.path, but that doesn't work if you already have a module defined (I find it very strange behavior)
nosklo's answer with examples
__init__.py files are empty.
main.py app/ -> __init__.py package_a/ -> __init__.py fun_a.py package_b/ -> __init__.py fun_b.py
def print_a(): print 'This is a function in dir package_a'
from app.package_a.fun_a import print_a def print_b(): print 'This is a function in dir package_b' print 'going to call a function in dir package_a' print '-'*30 print_a()
from app.package_b import fun_b fun_b.print_b()
if you run
$ python main.py it returns:
This is a function in dir package_b going to call a function in dir package_a ------------------------------ This is a function in dir package_a
- main.py does:
from app.package_b import fun_b
- fun_b.py does
from app.package_a.fun_a import print_a
so file in folder
package_b used file in folder
package_a, which is what you want. Right??
main.py setup.py app/ -> __init__.py package_a/ -> __init__.py module_a.py package_b/ -> __init__.py module_b.py
- You run
Alternatively 2 or 3 could use:
from app.package_a import module_a
That will work as long as you have
app in your PYTHONPATH.
main.py could be anywhere then.
So you write a
setup.py to copy (install) the whole app package and subpackages to the target system's python folders, and
main.py to target system's script folders.