Python Toolchain
One tool set for every Entirius Python repository (entirius-py-*, entirius-django-*, entirius-service-*), so
the same commands work in each of them.
The Stack
Section titled “The Stack”| Layer | Tool | Replaces / forbidden |
|---|---|---|
| env + deps + lockfile | uv (uv.lock committed) | bare pip install, poetry, pipenv |
| lint + format | ruff | black, flake8, isort |
| tests | pytest (+ pytest-django in Django services/modules) | nose; unittest as runner |
| pre-commit hooks | pre-commit (ruff + MPL header + gitleaks) | manual discipline |
| task runner | Makefile (shared target names) | ad-hoc scripts in scripts/, just |
| build backend | hatchling | setuptools, setup.py |
| project config | pyproject.toml (single source) | requirements.txt, setup.cfg |
| Python | 3.11 or newer | older versions |
A change to the stack is made here first, not in one repository.
- Dependencies only in
pyproject.toml: norequirements.txt/setup.py. - A lower bound on every new dependency:
>=, never==. Older packages still declare some dependencies with no bound; add the bound when you touch the line. uv.lockcommitted in every repo (services and libraries); CI installs withuv sync --frozen(environment exactly from the lock), see the decision below.- Ruff = lint + format in one; configured in
pyproject.toml([tool.ruff]). - One ruff configuration:
line-length = 120, rulesE,W,F,I,B,C4,UP,DJ,S(E501ignored: line length isruff format’s job). Copy[tool.ruff]from a released module’spyproject.toml, for example entirius-django-pim. - pre-commit is installed in every clone: ruff, the MPL header and gitleaks run before a commit, and CI runs the same checks again.
- Type hints on public functions; built-in generics and
|instead oftyping.List/Optional/.... - Inspect the env with
uv pip list, not barepip: uv does not install pip into the venv; the systempipshows a different environment.
uv.lock Committed Everywhere
Section titled “uv.lock Committed Everywhere”The lock is committed in libraries as well as in the service, as uv recommends. git pull and uv sync --frozen
then give the same environment on every machine and in CI. .gitattributes collapses the diff
(uv.lock linguist-generated=true). A conflict in the lock is resolved by running uv lock again, never by hand.
Repo Skeleton
Section titled “Repo Skeleton”A new repository copies the toolchain files from a released one: pyproject.toml, Makefile, the CI workflows,
.pre-commit-config.yaml, .gitignore, .gitattributes, .license-header.txt. Copy from
entirius-django-pim for a Django module and from
entirius-py-bievents for a library.
Build a Module goes through the files one by one.
- Makefile Convention: the targets that wrap these tools
- CI/CD: the same tools in the pipeline
- Secret Scanning: the gitleaks hook
- Licensing: the header hook