If you get import errors like ImportError: attempted relative import with no known parent package
or ImportError: Attempted relative import in non-package
, then you are running into Python’s relative import restrictions. Ugh! Python’s import system can be confusing, even for people who have experience with Python.
If you are working on a web project that uses a framework like FastAPI (or something similar), then you probably won’t run into import errors because the project files are usually organized to handle imports properly. However, if you are working on an analytics or data science project and your files and folders are not organized to handle Python imports properly, then you will need to find a solution to resolve relative imports.
When you import a module, Python will search for that module in the following locations:
sys.modules
: This is a cache of all modules that have been previously imported.sys.modules
, then Python will proceed to search through a list of built-in modules. These are modules that come pre-installed with Python and can be found in the Python Standard Library.sys.path
: If the name still isn’t found in the built-in modules, Python then searches for it in a list of directories defined by sys.path
. This list usually includes the current directory, which is the directory from which the script was run.So how do you get imports to work from anywhere? Let’s use this project directory as an example:
project_root/
├── main.py
├── shared/
│ └── constants.py
├── compute/
│ └── calculations.py
└── alter/
└── modifications.py
Let’s say that you have some constant values in the constants.py
file that you want to import into the calculations.py
and modifications.py
files. You can modify sys.path
at runtime so that it contains the parent directory for constants.py
. For example, you can add the following code at the top of the calculations.py
and modifications.py
files:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
This is another, slightly altered, option that references the relative path to the file instead of the relative path to the file’s parent directory:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
So you can work around Python’s relative import restrictions by adding the corresponding parent directory to sys.path
. No more relative import errors! Yay!