Import Python modules from another directory
Organize code as an importable package, install it for development, or load a trusted file explicitly when ordinary package imports are not appropriate.
For project code, prefer a package import or an editable installation. Changing sys.path can help a short script, but a stable package layout avoids depending on how an IDE or shell happened to start Python.
Import through the package layout
project/
main.py
utils/
__init__.py
helpers.py
scripts/
__init__.py
tool.py
If helpers.py defines my_function, either main.py or scripts/tool.py can use:
from utils.helpers import my_function
From project, run the tool as a module:
python -m scripts.tool
The directory containing the top-level packages must be discoverable. Adding __init__.py alone does not make an arbitrary parent directory appear on the import path.
Install the project in the active environment
For a project with valid packaging metadata and package discovery configured in pyproject.toml:
python -m pip install -e .
An editable install makes its declared packages importable from that environment while keeping development source editable. The mere presence of a pyproject.toml is not sufficient: its build backend and packaging configuration must support the project. An unrelated working-directory file can still shadow an installed module.
Add a path for a small script
import sys
sys.path.append("/path/to/utils")
import helpers
Replace that path with a real trusted directory. An absolute path avoids dependence on the working directory, but remains machine-specific. Appending puts the directory after existing entries, so an earlier helpers can win. Prepending changes precedence and can shadow other packages; neither operation is a substitute for a deliberate package name.
Load a trusted file by path
import importlib.util
import sys
def load_file(name, path):
if name in sys.modules:
raise ValueError(f"Module already loaded: {name}")
spec = importlib.util.spec_from_file_location(name, path)
if spec is None or spec.loader is None:
raise ImportError(f"Cannot create an import spec for {path}")
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module
try:
spec.loader.exec_module(module)
except BaseException:
sys.modules.pop(name, None)
raise
return module
# Supply an existing trusted file:
# helpers = load_file("project_helpers", "/path/to/utils/helpers.py")
# helpers.my_function()
This executes the file. It is not a sandbox, and registration cleanup cannot undo the module's side effects. A standalone name also does not provide the package context needed for arbitrary relative imports inside that file.
FAQ
Why does importing work only in the IDE? Compare interpreter selection, editable installations, working directory, and sys.path. The IDE may add a source directory that the command line never sees.
Why does from ..utils fail? The dots refer to package ancestry, not arbitrary parent directories. Run an importable package module with -m and use a layout that actually has the required parent package.
How do I identify a name collision? Check getattr(module, "__file__", None) and module.__spec__. Some built-in or namespace modules do not have a conventional file path.
References
Contact us
Join the community
to join the community
Try Guance
Start online and pay only for what you use.
Get startedChoose a Guance plan