Skip to main content

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.

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
note

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
warning

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:

  1. Use Absolute Imports (from my_package.module import func) for clarity and fewer runtime errors.
  2. Use Relative Imports (from .module import func) if you need the package to be portable (renamable).
  3. Never run package files directly (python package/file.py) if they use relative imports. Always use python -m package.file or an entry point script (main.py).