src/ layout, editable installs (pip install -e .),
and unittest discovery so your code runs the same in PyCharm, the terminal, and CI.
Python projects often start as a few scripts and quickly grow into something that needs repeatable structure. The most common pain point is imports: code runs in an IDE but fails in the terminal (or in CI).
The approach in this paper solves that by making Python treat your project as a real installable package:
src/ layout so your package is clearly separated from test code and project tooling.pip install -e .) so imports work without environment hacks.unittest discover in a way that is deterministic and reproducible.PYTHONPATH tricks.
src/ + editable install# Install your package into the active venv (editable)
python -m pip install -e .
# Run unittest discovery from project root
python -m unittest discover -s tests -t . -v
PYTHONPATH=src can make things “work”, but it’s a manual override. A professional setup installs the package
so imports work naturally without extra environment variables.
Python does not “know what a project is.” It only knows how to import modules from locations on
sys.path—a list of directories searched during import.
Typical entries in sys.path include: the current working directory, standard library paths, and your environment’s
site-packages directory (where installed packages live).
site-packages automatically.
That is why pip install -e . is such a reliable approach.
# Quick proof: show what Python will search during imports
python -c "import sys; print('\n'.join(sys.path[:6]))"
src/ Layout
In a professional Python package, your importable code lives under src/.
Tests and tooling live alongside it but are not mixed into the import path by accident.
test_codex/
pyproject.toml
README.md
src/
test_codex/
__init__.py
app.py
tests/
__init__.py
test_smoke.py
test_codex is the package.pip install -e . Actually DoesAn editable install registers your project package with the environment, but links it back to your working directory. That means:
# From the project root, with your venv activated:
python -m pip install -e .
# Verify the package is importable:
python -c "import test_codex; print(test_codex.__file__)"
PYTHONPATH,
your results depend on how each tool sets the environment.
This is the discovery command used in a reproducible setup:
python -m unittest discover -s tests -t . -v
discover — automatically finds tests-s tests — start searching in the tests/ folder-t . — treat the project root as the top-level import base-v — verbose output (shows each test run)tests/__init__.py was included-t is used, unittest expects the start directory (tests) to be importable.
Adding tests/__init__.py makes tests a package, so unittest can import
tests.test_smoke reliably.
src/test_codex/app.pydef add(a: int, b: int) -> int:
return a + b
tests/test_smoke.pyimport unittest
from test_codex.app import add
class TestSmoke(unittest.TestCase):
def test_add(self):
self.assertEqual(add(2, 3), 5)
if __name__ == "__main__":
unittest.main()
./run_tests.sh#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
PY=".venv/bin/python"
if [[ ! -x "$PY" ]]; then
echo "ERROR: .venv missing. Create it with: python -m venv .venv"
exit 1
fi
# Ensure editable install so imports work without PYTHONPATH.
"$PY" -m pip install -e . >/dev/null
"$PY" -m unittest discover -s tests -t . -v
cd /home/fred/PycharmProjects/test_codex
python -m venv .venv
source .venv/bin/activate
test_codex importable everywhere.
python -m pip install -U pip
python -m pip install -e .
python -c "import test_codex; import test_codex.app; print('ok')"
python -m unittest discover -s tests -t . -v
.venv/bin/python.src as “Sources Root” is fine (and helpful), but the editable install is what makes the CLI match.A professional Python workflow is mostly about making your environment deterministic: the same commands behave the same everywhere. The combination of:
src/ package layoutpyproject.toml with package discoverypip install -e . editable installsgives you a foundation that scales from a quick test project to production tooling.