How script location, CWD, and relative imports interact
🧱 Scenario: A Modular Package Layout
Suppose you have this structure:
project_root/
├── main.py
├── package/
│ ├── __init__.py
│ ├── utils.py
│ └── logger/
│ ├── __init__.py
│ └── formatter.py
You want main.py
to import from package.utils
, and utils.py
to import from logger.formatter
.
🧪 Case 1: Running main.py
Directly
bash
cd project_root
python main.py
✅ What Works
main.py
can do:python
from package import utils
utils.py
can do:python
from .logger import formatter # ✅ relative import
Because:
sys.path[0]
isproject_root
package
is a valid top-level packageRelative imports inside
package
work as expected
❌ Case 2: Running utils.py
Directly
bash
cd project_root/package
python utils.py
❌ What Breaks
from .logger import formatter
will raise:ImportError: attempted relative import with no known parent package
Because:
Python treats
utils.py
as a standalone script, not part of a packageRelative imports only work when the module is part of a package
✅ Solution: Use -m
to Run as a Module
Instead of running utils.py
directly, do:
bash
cd project_root
python -m package.utils
Now Python treats package
as a proper package, and relative imports work.
🧠 Summary: Best Practices
Task | Recommended Approach |
---|---|
Run top-level script | python main.py from project root |
Run submodule with imports | python -m package.submodule from root |
Avoid broken relative imports | Don’t run submodules directly as scripts |
Debug import issues | Print sys.path and __name__ |
🧪 Bonus Tip: Debugging Imports
Add this to any script:
python
import sys
print("sys.path:", sys.path)
print("__name__:", __name__)
This helps you see:
Where Python is looking for modules
Whether the script is being run as
__main__
or as part of a package