Sibling module import fails in production despite working locally
0 reputation · 15 Nov 2021, 10:13 UTC
0 reputation · 15 Nov 2021, 10:13 UTC
When a Python script is executed directly with python path/to/script.py, CPython automatically places the script’s directory at the front of sys.path, allowing imports of sibling modules without installation. In production, the same code is often launched via a process manager, as a module (python -m package.module) or from a different working directory, which removes that implicit entry and can change the effective PYTHONPATH or user‑site settings. Additionally, file‑system case sensitivity differs between developer workstations and Linux servers, turning a case‑insensitive match into a ModuleNotFoundError. The reliance on the implicit current‑directory import is an unresolved design decision that makes code fragile when the entry point is not the package root and no warning is emitted.
What strategies ensure that sibling‑module imports remain reliable across development and production executions? Should projects avoid depending on the script‑directory entry in sys.path and instead use explicit package structures or adjustable paths? How can automated checks detect reliance on implicit current‑directory imports before deployment?
35275 reputation · 15 Nov 2021, 14:59 UTC
When you run python path/to/script.py, CPython inserts the directory that contains script.py at sys.path[0]. This lets a statement like import sibling succeed because the sibling module lives next to the script. When the same code is started as a module (python -m package.module) or from a different working directory, that automatic entry is absent; imports then rely only on PYTHONPATH or the installed package layout. Consequently, code that works locally can raise ModuleNotFoundError in production.
__init__.py at the top level.pip install -e . from the repository root. This places the package root on sys.path as a normal entry.from package import sibling) or explicit relative imports (from . import sibling) inside the package.sys.path at runtime; rely on the installed package location instead.python path/to/script.pypython -m package.module (where package is the top‑level package)ImportError and without any manual sys.path modifications.importlib.util.find_spec('package.sibling') returns a non‑None spec when the package root is on sys.path.In a test or lint step, compare sys.path[0] with the directory of the executed script. If they match and the import succeeds, flag the import as fragile. A simple check:
import sys, pathlib
script_dir = pathlib.Path(sys.argv[0]).resolve().parent
if sys.path[0] == str(script_dir):
print('Warning: import relies on implicit cwd entry')
Treat any warning as a signal to refactor the import to an absolute or relative form and ensure the package is installed.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.