Programming

Fix Relative Imports Python: Non-Package Error Guide

Resolve 'attempted relative import in non-package' error for relative imports Python across subpackages like app/sub1 to sub2. Use absolute imports or python -m flag for clean fixes without sys.path hacks.

1 answer 2 views

Why the error happens

from ..sub2 import mod2 is a relative import.
Relative imports only work when the module that contains the import is imported as part of a package.
If you run mod1.py directly (python mod1.py) it is treated as a top‑level script, not as a module inside the app package, so Python raises

Attempted relative import in non‑package

Clean ways to import mod2

Method How to use When to use
Absolute import from app.sub2 import mod2 Works whether you run mod1.py directly or import it from elsewhere.
Relative import (inside a package) from ..sub2 import mod2 Use only when mod1.py is imported as part of the app package.
Run as a module python -m app.sub1.mod1 Keeps the relative import working without changing the code.

Example

app/sub1/mod1.py

python
# Absolute import – works in all cases
from app.sub2 import mod2

# or, if you prefer a relative import and will run as a module
# from ..sub2 import mod2

def main():
 print(mod2.some_function())

if __name__ == "__main__":
 main()

Running the script

bash
# Using the absolute import – no special command needed
python app/sub1/mod1.py

# Using the relative import – run as a module
python -m app.sub1.mod1

If you need to keep mod1.py executable as a script

python
# app/sub1/mod1.py
import sys
import os

# Adjust the path so that the package root is on sys.path
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from app.sub2 import mod2 # now works

def main():
 print(mod2.some_function())

if __name__ == "__main__":
 main()

Best practice

  • Keep __init__.py files empty (they just mark directories as packages).
  • Prefer absolute imports (from app.sub2 import mod2) for clarity and to avoid the “non‑package” error.
  • If you need to run a module directly, either use the -m flag or add the package root to sys.path (the minimal hack shown above).

This approach removes the error without any sys.path manipulation in the production code and keeps the package structure clean.

The “attempted relative import in non-package” error hits when you try relative imports Python style—like from ..sub2 import mod2 in app/sub1/mod1.py—but run the file directly as a script. Python sees it as a standalone top-level module, not part of the app package hierarchy, so relative imports fail. Fix relative imports Python cleanly with absolute imports (from app.sub2 import mod2) that work everywhere, or run via python -m app.sub1.mod1 to treat it as a package without sys.path hacks.


Contents


Understanding Relative Imports in Python Packages

Ever stared at your package structure, convinced everything’s set up right, only to watch relative imports Python crumble? You’re not alone. Relative imports shine in hierarchical setups like yours—app/sub1/mod1.py pulling from app/sub2/mod2.py—because they keep paths portable during refactors.

The official Python documentation spells it out: relative imports use leading dots. A single dot (.) means “from the current package,” double dots (..) climb to the parent. So from ..sub2 import mod2 tells Python: “Grab mod2 from my parent’s sub2 sibling.” But here’s the catch—they demand __package__ be set properly, which only happens when your module runs as part of a package.

Absolute imports, by contrast, start from the root: from app.sub2 import mod2. No dots, no drama. The Python tutorial on modules shows this in action for intra-package references, like from . import sibling_module. Empty __init__.py files? Totally fine—they just flag directories as packages.

Think of it like a family tree. Relative imports navigate siblings and parents locally. Absolute ones shout the full address from the top. For shared subpackages—say sub2 with a base class used by sub1, sub3, and beyond—relative feels intuitive at first. But execution context decides if it works.


Why the ‘Attempted Relative Import in Non-Package’ Error Occurs

That error message? It’s Python’s way of saying, “Hey, relative imports aren’t for scripts run solo.” Fire up python app/sub1/mod1.py directly, and __name__ becomes '__main__'. No package context. No __package__ attribute. Boom—Attempted relative import in non-package.

Stack Overflow threads nail this repeatedly. One detailed discussion traces it to direct execution: your mod1.py isn’t “imported,” it’s launched. Relative syntax assumes a parent package, but Python treats it like a flat script. Even with __init__.py everywhere, that alone doesn’t create the execution context.

PEP 328 formalized relative imports back in Python 2.5, but PEP 366 clarified __main__ limitations. Run directly? Relative imports disabled. It’s not a bug—it’s by design to avoid namespace pollution in scripts.

Quick test: add print(__name__, __package__) to mod1.py. Direct run? __main__ None. Imported properly? app.sub1.mod1 'app.sub1'. Mystery solved.


Verifying Your Directory Structure and Package Setup

Before fixes, double-check your tree. Yours should look like this:

app/
├── __init__.py
├── sub1/
│ ├── __init__.py
│ └── mod1.py
├── sub2/
│ ├── __init__.py
│ └── mod2.py
└── subX/ # If you have more
 ├── __init__.py
 └── modX.py

From the project root (where app/ sits), navigate there in your terminal. Empty __init__.py files mark packages—no code needed. The Real Python guide stresses this: __path__ in __init__.py enables subpackage discovery.

Pitfall? Missing __init__.py in app/ itself. Python 3.3+ has namespace packages, but explicit ones are safer for relative imports Python. Test with python -c "import app.sub1.mod1" from root. No error? Structure’s good.

For shared sub2—maybe holding a DatabaseConnection class—everyone imports it similarly. Relative keeps it tight; absolute scales better.


Solution 1: Execute Modules as Packages Using the -m Flag

Want to keep from ..sub2 import mod2? Run as a module. From the project root (parent of app/), use:

bash
python -m app.sub1.mod1

The -m flag tells Python: “Treat app.sub1.mod1 as a package module.” __package__ sets to 'app.sub1'. Relative imports fire up. No code changes. Perfect for development or entry points.

In app/sub1/mod1.py:

python
from ..sub2 import mod2 # Now works!

def main():
 print(mod2.some_function()) # Assuming mod2 has this

if __name__ == "__main__":
 main()

And app/sub2/mod2.py for completeness:

python
def some_function():
 return "Hello from sub2!"

This mirrors Finxter’s quick fix. Why love it? Maintains relative imports Python purity across subpackages. Drawback? Must run from root, pass args carefully (python -m app.sub1.mod1 arg1 works).

For production? Tools like setuptools or poetry handle this seamlessly.


Solution 2: Switch to Absolute Imports for Simplicity

Tired of context games? Go absolute: from app.sub2 import mod2. Works direct (python app/sub1/mod1.py) or imported. Portable across projects. No -m needed.

Update mod1.py:

python
# Absolute import – bulletproof
from app.sub2 import mod2

def main():
 print(mod2.some_function())

if __name__ == "__main__":
 main()

Run anywhere:

bash
# From anywhere with app/ in sys.path or current dir
python app/sub1/mod1.py

Real Python weighs pros: clarity (full path visible), no execution quirks. Cons? Refactor app name? Update everywhere. But IDEs handle that.

For shared subpackages, absolute shines—sub1, subX both from app.sub2 import mod2. Future-proof.

Method Pros Cons
Relative (from ..sub2) Short, refactor-friendly Needs package context
Absolute (from app.sub2) Always works, explicit Verbose if deep

Best Practices for Shared Subpackages Across Your App

Building for sub1, sub2, subX sharing? Prioritize absolute imports. They’re explicit, debug-friendly. Keep __init__.py minimal—maybe from .mod2 import * for convenience, but sparingly.

Structure tip: Central app/common/ for true shared stuff, import as from app.common import utils. For entry points, use setup.py or pyproject.toml:

toml
[project.scripts]
mod1 = "app.sub1.mod1:main"

Then mod1 runs packaged automatically.

Avoid hacks like the sample’s sys.path.append(os.path.dirname(...))—it’s a minimal one-liner for scripts, but pollutes global paths. Production? No. Use virtualenvs, pin paths via PYTHONPATH.

Run tests? pytest or tox respects package structure. Document: “Run with python -m app.sub1.mod1 for relative imports Python.”


Common Pitfalls, Troubleshooting, and Alternatives

Still stuck? Check:

  • Current dir: Always from project root for -m.
  • Python version: 3.0+ handles this; older? __future__.absolute_import.
  • Nested depth: Triple dots (...) for grandparents.
  • Circular imports: Rare, but refactor.

One SO thread debunks “just add __init__.py” myth. Another warns against launchers.

Alternatives? importlib.import_module('app.sub2.mod2') dynamically. Or pathlib for paths. But stick to basics.

IDE woes? PyCharm/VS Code: Mark app/ as sources root.


Sources

  1. Python 3 Reference: The import system — Official rules for relative and absolute imports: https://docs.python.org/3/reference/import.html
  2. Python Tutorial: More on Modules — Explains package structure and intra-package imports: https://docs.python.org/3/tutorial/modules.html
  3. PEP 328: Imports: Multi-Line and Absolute/Relative — History and syntax for relative imports: https://peps.python.org/pep-0328/
  4. Absolute vs Relative Imports in Python — Comparison of import strategies with examples: https://realpython.com/absolute-vs-relative-python-imports/
  5. Relative imports for the billionth time — Stack Overflow solution for relative import errors: https://stackoverflow.com/questions/14132789/relative-imports-for-the-billionth-time
  6. How to fix “Attempted relative import in non-package” — Common pitfalls with init.py: https://stackoverflow.com/questions/11536764/how-to-fix-attempted-relative-import-in-non-package-even-with-init-py
  7. PEP 366: Main module explicit relative imports — Handling relative imports in main: https://peps.python.org/pep-0366/

Conclusion

Relative imports Python work great inside packages—stick to python -m app.sub1.mod1 if that’s your vibe. But for reliability across subpackages, absolute imports like from app.sub2 import mod2 win: no errors, no fuss. Test your structure, prefer explicit paths, and skip hacks. Your app stays clean, scalable, ready for growth.

Authors
Verified by moderation
Fix Relative Imports Python: Non-Package Error Guide