Style: PEP 8, black, ruff (formatting and linting)
Consistent code style is not a matter of taste — it is about reducing the cost of reading. In ZEUS the backend (FastAPI + SQLAlchemy + ARQ) is written by several people, so we enforce style automatically rather than in PR comments. Two tools handle 95% of the work: black (formatting) and ruff (linting, and largely an isort replacement too).
PEP 8 in a nutshell
PEP 8 is Python's official style guide. The things we care about most:
- 4 spaces for indentation, never tabs.
snake_casefor functions and variables,PascalCasefor classes,UPPER_CASEfor constants.- Line length: at ProfessNet 88 characters (the black default), not 79.
- Imports: stdlib → third-party → local, separated by a blank line.
black — the end of formatting debates
black is "uncompromising": you don't configure the style, you accept it.
# bad — manual, inconsistent formatting
d = {'host':probe.host,'forest':probe.forest , 'ts': now()}
# good — after `black .`
d = {"host": probe.host, "forest": probe.forest, "ts": now()}
ruff — the fast linter
ruff (written in Rust) combines flake8, isort, pyupgrade and dozens of other rules. It catches dead imports, unused variables and bad patterns.
# ruff: F401 'os' imported but unused → remove the import
import os
from app.probes import run_inventory
async def collect(forest: str) -> list[dict]:
return await run_inventory(forest)
The ProfessNet standard — pyproject.toml
We keep the configuration in a single pyproject.toml in the service directory:
[tool.black]
line-length = 88
target-version = ["py312"]
[tool.ruff]
line-length = 88
target-version = "py312"
[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B"] # style, errors, imports, upgrade, bugbear
ignore = ["E501"] # line length is handled by black
ProfessNet standard:
select = ["E", "F", "I", "UP", "B"]is our minimum.Ireplaces isort — we don't install isort separately.
Running it
ruff check --fix . # fix whatever can be fixed automatically
black . # format
ruff check . # check whether anything needs manual fixing
We run the same commands in pre-commit and in CI. A PR that fails ruff check
or changes anything after black --check does not get into main.
Tip: in VS Code set black as the formatter and enable "format on save", plus the
ruffextension — then you won't see a red CI locally.
The rule is simple: we don't debate formatting, because a machine does it for us. We move the energy from code review onto logic, security and naming — which we'll cover in the next lessons.