Coming from a static, strongly-typed language such as C# or Java, it was just a normal thing for me to reference other projects and custom types within those projects. No big deal.
But when I started using Python and wanted to import from parent directory, python would not allow it. While searching for a solution, I came to find out that in Python, importing a module from a parent or sibling directory is a different story altogether.
This post addresses this issue and proposes a solution.
Suppose this is the directory structure of a project:
Our script to run is
run.py, which will reference
a.py simply contains a single function:
def CommonFunction(): print("This is where a gets called")
run.py, we simply try to import
from common import a print("Execution of run starts") a.CommonFunction() print("Execution of run finishes")
We run the script in Visual Studio Code by right clicking the script and choosing the option:
Or run from the terminal:
You are going to get the following error:
ModuleNotFoundError: No module named 'common'
Starting from Python 3.3, implicit relative references are allowed no more. That means that the ability to reference a module in the parent directory is not possible and becomes a major limitation.
So in order to reference a module, the directory that contains a module must be present on PYTHONPATH – PYTHONPATH is an environment variable which contains the list of packages that will be loaded by Python upon execution. What is in PYTHONPATH is also present in
sys.path as well.
The directory from where a script or module is run is automatically added to PYTHONPATH. You can import any module that lies within this directory, but modules in its parent or sibling directories cannot be imported.
That is, unless you add the path to the desired module to PYTHONPATH or add it to
Add the following code to
run.py, I will explain the code in a bit:
import os, sys currentdir = os.path.dirname(os.path.realpath(__file__)) parentdir = os.path.dirname(currentdir) sys.path.append(parentdir) from common import a print("Execution of run starts") a.CommonFunction() print("Execution of run finishes")
Run the code again and you will see the expected output:
So what happened?
In the code, we import Python’s built-in modules
Then we get the current directory using the current file, then get the parent directory using the current directory and just
append it to the
sys.path. What this does is that it adds the parent directory to sys.path. So now we can import any package & its modules into our script, thanks to appending to
You can go as many levels up as you wish by getting the parent directory recursively.
We can also slightly adjust the above code for programmatically updating
sys.path as follows:
import sys, os, inspect currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) parentdir = os.path.dirname(currentdir) sys.path.insert(0, parentdir)
The change from the earlier code is that we use the
inspect module to get the current file, and then use
Difference between sys.path.insert and sys.path.append
The difference between
sys.path.append is that
append will add the given path to the end of the
sys.path‘s list, while
insert is going to insert it at the given index(0 in our case).
Python searches for the directories to import by going through the list. Now if you have a package or module with the same name, then Python is going to load the module that comes first in the list and will ignore the one that comes later. So if you have name conflicts and defined files/folders with the same name, you must insert that path to
sys.path at the first position.
Otherwise if you dont have naming conflicts, then the ordering of the imports does not matter and you can just append those paths to
Although this solution is a bit hacky and it is recommended to not meddle with
sys.path programmatically, it does get the job done when we have no other choice in Python but to import from parent directory using sys path. Using the
sys module in Python gives us a way to go up a layer or two.