Skip to content

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.

LayerToolReplaces / forbidden
env + deps + lockfileuv (uv.lock committed)bare pip install, poetry, pipenv
lint + formatruffblack, flake8, isort
testspytest (+ pytest-django in Django services/modules)nose; unittest as runner
pre-commit hookspre-commit (ruff + MPL header + gitleaks)manual discipline
task runnerMakefile (shared target names)ad-hoc scripts in scripts/, just
build backendhatchlingsetuptools, setup.py
project configpyproject.toml (single source)requirements.txt, setup.cfg
Python3.11 or newerolder versions

A change to the stack is made here first, not in one repository.

  • Dependencies only in pyproject.toml: no requirements.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.lock committed in every repo (services and libraries); CI installs with uv 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, rules E,W,F,I,B,C4,UP,DJ,S (E501 ignored: line length is ruff format’s job). Copy [tool.ruff] from a released module’s pyproject.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 of typing.List/Optional/....
  • Inspect the env with uv pip list, not bare pip: uv does not install pip into the venv; the system pip shows a different environment.

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.

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.