How to Handle Relative Imports Between Files in Python
Organizing Python code into packages is essential for scalability, but it often leads to the confusing ImportError: attempted relative import with no known parent package. This error occurs when developers try to run a file inside a package directly as a script, breaking Python's understanding of the package structure.
This guide explains how to correctly handle imports between sibling files, how to distinguish between Absolute and Relative imports, and how to execute package modules without triggering common import errors.
Understanding the Package Structure
Before importing, we need a clear structure. A directory becomes a "package" when it contains an __init__.py file (though Python 3.3+ makes this optional, it is still best practice for explicit package definition).
Example Structure:
my_project/
├── main.py # Entry point (outside the package)
└── my_package/ # The Package
├── __init__.py
├── database.py # Contains: def connect()
└── user.py # Needs to import connect() from database.py
In this scenario, user.py needs to use a function defined in database.py.
Method 1: Absolute Imports (Recommended)
Absolute imports specify the full path starting from the project's root directory (where sys.path starts). This is generally preferred because it is explicit and readable.
In my_package/user.py:
# ✅ Correct: Full path from the project root
from my_package.database import connect
def create_user():
db = connect()
print("User created")
Running the code:
You must run your application from the my_project root directory.
# Run the main entry point
python main.py
Absolute imports require that the top-level folder (my_project) is in sys.path. Running scripts from the root directory usually ensures this automatically.
Method 2: Relative Imports (For Internal Use)
Relative imports use dot notation to indicate current or parent directories. They are useful if you want to move the entire package to a different project without renaming internal links.
.(Single dot): Current directory...(Double dot): Parent directory.
In my_package/user.py:
# ✅ Correct: Import from the same directory
from .database import connect
# OR, if you just want the module
from . import database
In my_package/__init__.py:
It is common to expose key functions in the init file using relative imports.
from .user import create_user
from .database import connect
Relative imports only work when the file is imported as a module. You cannot run a file with relative imports directly as a script (e.g., python my_package/user.py will fail).
The "Script vs. Module" Trap
The most common error developers encounter is trying to run a file inside a package directly.
Example of Error
If you run python my_package/user.py while it contains from .database import connect, you get:
ImportError: attempted relative import with no known parent package
Why? When you run a file directly, Python sets its __name__ to '__main__' and does not know it belongs to a package. Therefore, the relative dot . has no meaning.
Solution: Run as a Module
If you need to test user.py individually, do not run it by file path. Run it as a module using the -m flag from the project root.
# ✅ Correct: Run as a module (no .py extension, use dots)
python -m my_package.user
Alternatively, use a separate main.py outside the package to handle execution logic.
Conclusion
To handle imports within a Python package effectively:
- Use Absolute Imports (
from my_package.module import func) for clarity and fewer runtime errors. - Use Relative Imports (
from .module import func) if you need the package to be portable (renamable). - Never run package files directly (
python package/file.py) if they use relative imports. Always usepython -m package.fileor an entry point script (main.py).