How to do relative imports in Python?
Solution 1
Everyone seems to want to tell you what you should be doing rather than just answering the question.
The problem is that you're running the module as '__main__' by passing the mod1.py as an argument to the interpreter.
From PEP 328:
Relative imports use a module's __name__ attribute to determine that module's position in the package hierarchy. If the module's name does not contain any package information (e.g. it is set to '__main__') then relative imports are resolved as if the module were a top level module, regardless of where the module is actually located on the file system.
In Python 2.6, they're adding the ability to reference modules relative to the main module. PEP 366 describes the change.
Update: According to Nick Coghlan, the recommended alternative is to run the module inside the package using the -m switch.
Solution 2
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.
Solution 3
main.py
setup.py
app/ ->
__init__.py
package_a/ ->
__init__.py
module_a.py
package_b/ ->
__init__.py
module_b.py
- You run
python main.py
. -
main.py
does:import app.package_a.module_a
-
module_a.py
doesimport app.package_b.module_b
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.
Solution 4
"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.
Solution 5
This is solved 100%:
- app/
- main.py
- settings/
- local_setings.py
Import settings/local_setting.py in app/main.py:
main.py:
import sys
sys.path.insert(0, "../settings")
try:
from local_settings import *
except ImportError:
print('No Import')
![Joril](https://i.stack.imgur.com/UK7Dc.png?s=256&g=1)
Joril
Updated on November 30, 2021Comments
-
Joril over 2 years
Imagine this directory structure:
app/ __init__.py sub1/ __init__.py mod1.py sub2/ __init__.py mod2.py
I'm coding
mod1
, and I need to import something frommod2
. How should I do it?I tried
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 emptyEdit2: I'm trying to do this because sub2 contains classes that are shared across sub packages (
sub1
,subX
, etc.).Edit3: The behaviour I'm looking for is the same as described in PEP 366 (thanks John B)
-
Xiong Chiamiov almost 15 yearsI'm using this snippet, combined with the imp module (as explained here [1]) to great effect. [1]: stackoverflow.com/questions/1096216/…
-
Nick Retallack about 14 yearsThe answer here involves messing with sys.path at every entry point to your program. I guess that's the only way to do it.
-
osjerick about 14 yearsProbably, sys.path.append(path) should be replaced with sys.path.insert(0, path), and sys.path[-1] should be replaced with sys.path[0]. Otherwise the function will import the wrong module, if there is already a module with the same name in search path. E.g., if there is "some.py" in current dir, import_path("/imports/some.py") will import the wrong file.
-
iElectric about 14 yearsI agree! Sometimes other relative imports will make precedance. Use sys.path.insert
-
levesque over 13 yearsHow would you replicate the behavior of from x import y (or *)?
-
ncoghlan over 13 yearsThe recommended alternative is to run modules inside packages using the
-m
switch, rather than by specifying their filename directly. -
auraham almost 12 yearsExcellent answer. Is there some way to import that way without install the package in PYTHONPATH?
-
Tom over 11 yearsI don't understand: where is the answer here? How can one import modules in such a directory structure?
-
Xiong Chiamiov over 11 years@Tom: In this instance, mod1 would
from sub2 import mod2
. Then, to run mod1, from within app, dopython -m sub1.mod1
. -
LarsH over 11 years@XiongChiamiov: does this mean you can't do it if your python is embedded in an application, so you don't have access to python command line switches?
-
PuercoPop about 11 yearsExcept one can't do relative imports from the 'main' module as the answer from John B. states
-
Alexey Kuzminich about 11 years@MattJoiner: It works if you run mod1.py as
python -m app.sub1.mod1
(from the parent dir ofapp
) as Pankaj wrote. -
jfs about 11 yearsNote: Already mentioned pep-366 (created around the same time as pep-3122) provides the same capabilities but uses a different backward-compatible implementation i.e., if you want to run a module inside a package as a script and use explicit relative imports in it then you could run it using
-m
switch:python -m app.sub1.mod1
or invokeapp.sub1.mod1.main()
from a top-level script (e.g., generated from setuptools' entry_points defined in setup.py). -
nosklo over 10 yearsSuggested additional reading: blog.habnab.it/blog/2013/07/21/python-packages-and-you
-
MestreLion over 10 yearsBest answer IMHO: not only explains why OP had the issue, but also finds a way to solve it without changing the way his modules do imports. Afterall, OP's relative imports were fine. The culprit was the lack of access to outer packages when directly running as script, something
-m
was designed to solve. -
JeremyKun about 10 yearsAlso take note: this answer was 5 years after the question. These features were not available at the time.
-
Rotareti almost 8 yearsIf you want to import a module from the same directory you can do
from . import some_module
. -
Vit Bernatik over 7 yearsthank you! all ppl were forcing me to run my script differently instead of telling me how to solve it within script. But I had to change the code to use
sys.path.insert(0, "../settings")
and thenfrom local_settings import *
-
Nister over 7 years
sys.path.append('../')
works fine for me (Python 3.5.2) -
Spybdai over 7 yearsthen, one day, need to change name of app to test_app. what would happen? You will need to change all the source codes, import app.package_b.module_b --> test_app.package_b.module_b. this is absolutely BAD practice... And we should try to use relative import within the package.
-
byxor almost 7 yearsThis is essentially how
virtualenv
lets you manage your import statements. -
Tom Russell over 6 yearsI think this is fine since it localizes the hack to the executable and doesn't affect other modules which may depend on your packages.
-
x-yuri over 6 yearsTo make it clear, when you do
from .m import whatever
in a script you pass as an argument to interpreter, it basically resolves tofrom __main__.m import whatever
. Which makes it look for__main__/m.py
. -
mrgloom almost 6 yearsIt's not clear, please specify full usage of this script to solve OP problem.
-
jpmc26 about 5 years"Everyone seems to want to tell you what you should be doing rather than just answering the question." Well, good. That's the way getting help writing software should be! When I fly in the face of good practice, I want to know.
-
RecencyEffect over 4 years+1 for using setuptools and entry points - it is a proper way to set up scripts that will be run from the outside, in a well-defined location, as opposed to endlessly hacking PYTHONPATH
-
Joril over 4 yearsThis is roughly the same as manipulating
sys.path
, sincesys.path
gets initialized fromPYTHONPATH
-
Giorgos Myrianthous over 4 years@Joril That's correct but
sys.path
needs to be hardcoded in the source code in contrast toPYTHONPATH
which is an environment variable and can be exported. -
Admin over 3 yearsDidn't found the definition of 'run' on the peps. For me, it doesn't look like 'running' is the best definition (for the ant pattern) cause at the end the 'interpretation' will link the dependencies and not actually 'run' it at the sense of executing immediately. Reference 1 and reference 2
-
AstroFloyd about 3 years@Tom I suppose the answer is in the PEP 366 and boils down to something like
if(__name__ == "__main__" and __package__ is None): __package__ = "app"
-
AstroFloyd about 3 years@jpmc26 Agreed, but I think it should be a comment then, not an answer.
-
Jesse H. about 3 yearsThis is the answer that helped me and it also helped me condense my thought down to this: In order to run a Python script which contains relative imports, I must run the script as a module while
$ PWD
is its parent directory like$ python -m app.main
. For clarity,$ python -m <main_directory>.<script_with_relative_imports>