Import from sibling directory
Asked Answered
C

3

42

I have a Python class called "ClassA" and another Python class which is supposed to import ClassA which is "ClassB". The directory structure is as follows:

MainDir
../Dir
..../DirA/ClassA
..../DirB/ClassB

How would I use sys.path so that ClassB can use ClassA?

Claypool answered 27/12, 2010 at 22:41 Comment(2)
It's called relative imports and has quite a bit of googleable material and SO questions.Raffin
#279737Fredenburg
L
17

You really should be using packages. Then MainDir is placed at a point in the file system on sys.path (e.g. .../site-packages), then you can say in ClassB:

from MainDir.Dir.DirA import ClassA # which is actually a module

You just have to place files named __init__.py in each directory to make it a package hierarchy.

Lancer answered 27/12, 2010 at 22:57 Comment(5)
I added MainDir to the sys.path and tried your solution, but it just says there is no module named MainDir.Dir.DirA, and there are init.pys in all directories.Claypool
Don't add MainDir, add its parent directory. If you add MainDir (if that is not the package root, that is fine), then import like from Dir.DirA import ClassA instead.Lancer
It took me a while to figure out that "turning your code into a package" means all of 1) putting an __init__.py in the top dir of your code and 2) adding the parent directory of the top dir to your PYTHONPATH and 3) setting the __package__ variable in your Python program to the name of the directory that contains __init__.py. All is working now, thanks!Tabasco
if ClassA.py code defines import ClassAA where ClassAA.py is also in DirA, then the above method fails when ClassA is imported from ClassB. What is the correct way in this situation?Blistery
@Blistery Use a relative import import .ClassAA, or in ClassB import ..DirA.ClassAA.Lancer
G
53

as a literal answer to the question 'Python Import from parent directory':

to import 'mymodule' that is in the parent directory of your current module:

import os
parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
os.sys.path.insert(0,parentdir) 
import mymodule

edit Unfortunately, the __file__ attribute is not always set. A more secure way to get the parentdir is through the inspect module:

import inspect
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
Girgenti answered 21/3, 2012 at 13:54 Comment(1)
Remi - Thanks for the literal answer. I found this useful when writing test code for a python app. I can place the test code in a subdirectory, and I can begin to put tests in place without modifying the existing project. (In other words; converting the existing code to a module before having tests in place would be the incorrect order to do things from the perspective of managing the risk of introducing bugs to working code.) Your method of changing the module path is handy.Coagulate
V
31

You can use relative import (example from link, current module - A.B.C):

from . import D                 # Imports A.B.D
from .. import E                # Imports A.E
from ..F import G               # Imports A.F.G
Velvavelvet answered 27/12, 2010 at 22:47 Comment(5)
@Yakattak: Yes, but they should be in a package anyway ;)Raffin
this looks like the best and simplest answerSaddle
caution: relative imports rely on __name__ of modules, so if you ever intend to run the current module (which sets __name__ to __main__), the relative imports will failAlcock
What are the critera for calling it a package? Just that each of the subfolders contains an init.py?Construction
@Construction It means all three of 1) putting an __init__.py in the top directory of your code and 2) adding the parent directory of the top dir to your PYTHONPATH and 3) setting the __package__ variable in your Python program to the name of the directory that contains __init__.py.Tabasco
L
17

You really should be using packages. Then MainDir is placed at a point in the file system on sys.path (e.g. .../site-packages), then you can say in ClassB:

from MainDir.Dir.DirA import ClassA # which is actually a module

You just have to place files named __init__.py in each directory to make it a package hierarchy.

Lancer answered 27/12, 2010 at 22:57 Comment(5)
I added MainDir to the sys.path and tried your solution, but it just says there is no module named MainDir.Dir.DirA, and there are init.pys in all directories.Claypool
Don't add MainDir, add its parent directory. If you add MainDir (if that is not the package root, that is fine), then import like from Dir.DirA import ClassA instead.Lancer
It took me a while to figure out that "turning your code into a package" means all of 1) putting an __init__.py in the top dir of your code and 2) adding the parent directory of the top dir to your PYTHONPATH and 3) setting the __package__ variable in your Python program to the name of the directory that contains __init__.py. All is working now, thanks!Tabasco
if ClassA.py code defines import ClassAA where ClassAA.py is also in DirA, then the above method fails when ClassA is imported from ClassB. What is the correct way in this situation?Blistery
@Blistery Use a relative import import .ClassAA, or in ClassB import ..DirA.ClassAA.Lancer

© 2022 - 2024 — McMap. All rights reserved.