I've been struggling with relative imports on python.
My project structure looks like this:
root_dir
├── main.py
├── Pipfile
├── Pipfile.lock
├── unit_tests
│ ├── __init__.py
│ ├── test_first.py
│ └── test_second.py
└── my_package
├── __init__.py
├── first.py
├── second.py
└── third.py
I want to import a set of functions from a file that is located in my_package
into test_first.py
.
According to the official documentation the syntax should be the following:
from ..my_package import first
When I do that, I get the following exception:
Traceback (most recent call last):
File "/home/user/dev/root_dir/my_package/unit_tests/first.py", line 8, in <module>
from ..my_package import first
ImportError: attempted relative import with no known parent package
I have also tried to import the file by using the following syntax:
from root_dir.my_package import first
When I do that, I get the following exception:
ModuleNotFoundError: No module named 'root_dir'
It is important to mention that I am using pipenv
to handle the virtual environment.
Any idea why this is happening?
Thanks.
First, I'll give you the code that worked for me. Then, I'll give a brief explanation. Here's a short function that should let you import from the root directory.
import os, sys
def access_root_dir(depth = 1):
current_dir = os.path.dirname(os.path.realpath(__file__))
parent_dir = os.path.dirname(current_dir)
args: list = [parent_dir]
for _ in range(depth):
args.append('..')
rel_path = os.path.join(*args)
sys.path.append(rel_path)
# At the top of test_first.py
access_root_dir(2)
import root_dir
Since the root directory is a grandparent of test_first.py
, you need to go to depth 2:
I encountered the same problem in one of my projects and found
that imports from a parent directory were fixed by altering the sys.path
. Appending an absolute path to the root directory with something like
sys.path.append(abs_path_to_root)
doesn't seem to work unless everything is part of a package. Python won't access parent directories in imports by default.
# Case 1: Relative path to parent - works
current_dir = os.path.dirname(os.path.realpath(__file__))
relative_path = os.path.join(current_dir, '..')
sys.path.append(relative_path)
import parent_module_name # This works for me (Python 3.9)
# Case 2: Absolute path to parent - Doesn't work
current_dir = os.path.dirname(os.path.realpath(__file__))
parent_dir = os.path.dirname(current_dir)
sys.path.append(parent_dir)
import parent_module_name # raises ModuleNotFoundError