How can I do relative imports in Python?
Asked Answered
T

17

620

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 from mod2. 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 I found only "sys.path manipulation" hacks. Isn't there a clean way?


All my __init__.py's are currently empty

I'm trying to do this because sub2 contains classes that are shared across sub packages (sub1, subX, etc.).

The behaviour I'm looking for is the same as described in PEP 366 (thanks John B).

Thinner answered 16/9, 2008 at 14:24 Comment(4)
I recommend updating your question to make it more clear that you're describing the issue addressed in PEP 366.Zannini
It's a long winded explanation but check here: https://mcmap.net/q/14784/-python-packaging-for-relative-imports I answered a very similar question. I had this same problem until last night.Yukikoyukio
For those who wish to load a module located at an arbitrary path, see this: stackoverflow.com/questions/67631/…Jalopy
On a related note, Python 3 will change the default handling of imports to be absolute by default; relative imports will have to be explicitly specified.Alphonsoalphonsus
Z
384

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.

Zannini answered 16/9, 2008 at 14:48 Comment(11)
The answer here involves messing with sys.path at every entry point to your program. I guess that's the only way to do it.Mindszenty
The recommended alternative is to run modules inside packages using the -m switch, rather than by specifying their filename directly.Sestet
I don't understand: where is the answer here? How can one import modules in such a directory structure?Involution
@Tom: In this instance, mod1 would from sub2 import mod2. Then, to run mod1, from within app, do python -m sub1.mod1.Darcee
@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?Lucifer
@MattJoiner: It works if you run mod1.py as python -m app.sub1.mod1 (from the parent dir of app) as Pankaj wrote.Bicapsular
To make it clear, when you do from .m import whatever in a script you pass as an argument to interpreter, it basically resolves to from __main__.m import whatever. Which makes it look for __main__/m.py.Nebulose
"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.Simonize
@Involution I suppose the answer is in the PEP 366 and boils down to something like if(__name__ == "__main__" and __package__ is None): __package__ = "app"Penelopepeneplain
@Simonize Agreed, but I think it should be a comment then, not an answer.Penelopepeneplain
How does it answer the question? This just gave links to a couple of references. It is not immediately useful without more jumping over hoops and loops.Overdraw
A
165

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.

Adjudge answered 17/3, 2013 at 7:43 Comment(4)
Best 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.Provitamin
Also take note: this answer was 5 years after the question. These features were not available at the time.Carberry
If you want to import a module from the same directory you can do from . import some_module.Robby
This 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>Polacre
A
132
main.py
setup.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       module_a.py
    package_b/ ->
       __init__.py
       module_b.py
  1. You run python main.py.
  2. main.py does: import app.package_a.module_a
  3. module_a.py does import 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.

Amortizement answered 21/1, 2009 at 12:42 Comment(3)
Excellent answer. Is there some way to import that way without install the package in PYTHONPATH?Fecal
Suggested additional reading: blog.habnab.it/blog/2013/07/21/python-packages-and-youAmortizement
then, 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.Depreciate
O
55

"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.

Octal answered 19/11, 2011 at 16:5 Comment(3)
Note: 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 invoke app.sub1.mod1.main() from a top-level script (e.g., generated from setuptools' entry_points defined in setup.py).Actinozoan
+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 PYTHONPATHPohl
Didn'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 2Funest
D
48

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')
Duodiode answered 11/2, 2016 at 12:1 Comment(3)
thank 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 then from local_settings import *Mig
Can you explain your answer, please? For example, why does it work? How does it work? What is the gist? "Explanation is vital for a good answer."_. (But ***** ***** ***** without ***** ***** ***** "Edit:", "Update:", or similar - the answer should appear as if it was written today)Aft
@PeterMortensen it works because it's a hack. Python uses the path to look for modules. By default, the directory of where the script is executed from is in the path. This forces the directory that is up one level, called settings is inserted into that path. Like all hacks, this will work in a lot of situations but it's not how imports are intended to work in Python. Other methods are preferredMoppet
D
29

Explanation of nosklo's answer with examples:

Note: all __init__.py files are empty.

main.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       fun_a.py
    package_b/ ->
       __init__.py
       fun_b.py

app/package_a/fun_a.py

def print_a():
    print 'This is a function in dir package_a'

app/package_b/fun_b.py

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()

main.py

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??

Democratic answered 8/12, 2013 at 3:19 Comment(1)
This does not answer the question. The question is how to do relative imports; this shows only absolute imports.Luciolucita
D
24

Use:

def import_path(fullpath):
    """ 
    Import a file with full path specification. Allows one to
    import from anywhere, something __import__ does not do. 
    """
    path, filename = os.path.split(fullpath)
    filename, ext = os.path.splitext(filename)
    sys.path.append(path)
    module = __import__(filename)
    reload(module) # Might be out of date
    del sys.path[-1]
    return module

I'm using this snippet to import modules from paths.

Decasyllable answered 4/7, 2009 at 23:27 Comment(5)
I'm using this snippet, combined with the imp module (as explained here [1]) to great effect. [1]: stackoverflow.com/questions/1096216/…Darcee
Probably, 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.Shakta
I agree! Sometimes other relative imports will make precedance. Use sys.path.insertDecasyllable
How would you replicate the behavior of from x import y (or *)?Bon
It's not clear, please specify full usage of this script to solve OP problem.Farandole
N
13

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)

Nonferrous answered 2/3, 2012 at 22:58 Comment(2)
sys.path.append('../') works fine for me (Python 3.5.2)Kathlenekathlin
I think this is fine since it localizes the hack to the executable and doesn't affect other modules which may depend on your packages.Heliozoan
C
10

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 scripts directory.

import os.path
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
Charissa answered 7/1, 2013 at 4:26 Comment(0)
M
8

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
Medievalist answered 24/9, 2011 at 19:31 Comment(1)
Except one can't do relative imports from the 'main' module as the answer from John B. statesEmulsifier
C
8

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.

Cropland answered 9/6, 2015 at 15:22 Comment(1)
This does not answer the question. The question is how to use relative imports correctly, not "please just enable me to import the file".Luciolucita
P
2

From Python doc,

In Python 2.5, you can switch import‘s behaviour to absolute imports using a from __future__ import absolute_import directive. This absolute- import behaviour will become the default in a future version (probably Python 2.7). Once absolute imports are the default, import string will 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 string in your code

Psychosomatic answered 29/6, 2011 at 17:33 Comment(0)
R
2

On top of what John B said, it seems like setting the __package__ variable should help, instead of changing __main__ which could screw up other things. But as far as I could test, it doesn't completely work as it should.

I have the same problem and neither PEP 328 nor PEP 366 solve the problem completely, as both, by the end of the day, need the head of the package to be included in sys.path, as far as I could understand.

Reconstructionist answered 11/9, 2012 at 7:47 Comment(0)
R
1

I found it's easier to set the "PYTHONPATH" environment variable to the top folder:

bash$ export PYTHONPATH=/PATH/TO/APP

Then:

import sub1.func1
# ...more imports

Of course, PYTHONPATH is "global", but it didn't raise trouble for me yet.

Reformer answered 17/3, 2012 at 9:20 Comment(1)
This is essentially how virtualenv lets you manage your import statements.Tortuga
D
0

You have to append the module’s path to PYTHONPATH:

export PYTHONPATH="${PYTHONPATH}:/path/to/your/module/"
Dyche answered 25/3, 2020 at 10:13 Comment(2)
This is roughly the same as manipulating sys.path, since sys.path gets initialized from PYTHONPATHThinner
@Thinner That's correct but sys.path needs to be hardcoded in the source code in contrast to PYTHONPATH which is an environment variable and can be exported.Dyche
E
0

A hacky way to do it is to append the current directory to the PATH at runtime as follows:

import pathlib   
import sys
sys.path.append(pathlib.Path(__file__).parent.resolve())
import file_to_import  # the actual intended import

In contrast to another solution for this question this uses pathlib instead of os.path.

Efficacious answered 1/3, 2022 at 22:56 Comment(0)
O
-2

What a debate!

I am a relative newcomer to Python (but years of programming experience, and dislike of Perl) and am a relative layperson when it comes to the dark art of Apache setup, but I know what I (think I) need to get my little experimental projects working at home.

Here is my summary of what the situation seems to be.

If I use the -m 'module' approach, I need to:

  1. dot it all together;
  2. run it from a parent folder;
  3. lose the '.py';
  4. create an empty (!) __init__.py file in every subfolder.

How does that work in a CGI environment, where I have aliased my scripts directory, and want to run a script directly as /dirAlias/cgi_script.py??

Why is amending sys.path a hack? The Python documentation page states: "A program is free to modify this list for its own purposes." If it works, it works, right? The bean counters in Accounts don't care how it works.

I just want to go up one level and down into a 'modules' directory:

.../py
      /cgi
      /build
      /modules

So my 'modules' can be imported from either the CGI world or the server world.

I've tried the -m/modules approach but I think I prefer the following (and am not confused how to run it in CGI space):

  1. Create XX_pathsetup.py in the /path/to/python/Lib directory (or any other directory in the default sys.path list). 'XX' is some identifier that declares an intent to set up my path according to the rules in the file.

  2. In any script that wants to be able to import from the 'modules' directory in above directory config, simply import XX_pathsetup.py.

And here's my really simple XX_pathsetup.py file:

import sys, os
pypath = sys.path[0].rsplit(os.sep, 1)[0]
sys.path.insert(0, pypath + os.sep + 'modules')

It is not a 'hack', IMHO. It is one small file to put in the Python 'Lib' directory and one import statement which declares intent to modify the path search order.

Ornas answered 18/2, 2023 at 13:56 Comment(1)
This answer is wrong on many levels. __init__.py files have not been required for marking packages since Python 3.3 and they are intended for a completely orthogonal purpose. They are never required to be empty; it's just less work to make an empty file than a non-empty one. Aside from that, please keep in mind that this is not a discussion forum and answers are expected to get directly to the point without talking about personal experiences or related problems you have tried to solve (please read How to Answer). Finally, why are you working directly with CGI in 2023?Luciolucita

© 2022 - 2024 — McMap. All rights reserved.