Conventions & Style Guide
Agreed Python idioms for the team - formatting, naming, typing, errors, and commits - enforced by ruff in CI and documented here so reviews focus on design, not taste.
Search across all documentation pages
Agreed Python idioms for the team - formatting, naming, typing, errors, and commits - enforced by ruff in CI and documented here so reviews focus on design, not taste.
from __future__ import annotations
from pathlib import Path
DATA_DIR = Path(__file__).resolve().parent / "data"
def load_config(path: Path) -> dict[str, str]:
try:
text = path.read_text(encoding="utf-8")
except OSError as exc:
raise ConfigError(f"cannot read {path}") from exc
return parse_env(text)When to reach for this:
# modules/billing/services/tax.py
from decimal import Decimal
from billing.domain.models import LineItem
from billing.settings import Settings
class TaxService:
def __init__(self, settings: Settings) -> None:
self._rate = Decimal(settings.vat_rate)
def compute(self, items: list[LineItem]) -> Decimal:
subtotal = sum((i.unit_price * i.quantity for i in items), start=Decimal("0"))
return (subtotal * self._rate).quantize(Decimal("0.01"))Commit message:
feat(billing): apply VAT to EU line items [BILL-91]
Uses Decimal for money math. Adds regression test for zero-quantity lines.What this demonstrates:
from __future__ import annotations for forward refsDecimal for currency - not float_rate attribute; public typed methodspyproject.toml.snake_case functions, PascalCase classes, SCREAMING_SNAKE constants.from module import *.| Topic | Convention |
|---|---|
| Strings | f-strings preferred |
| Paths | pathlib.Path not os.path.join |
| Exceptions | Specific types; raise ... from exc |
| Logging | logging.getLogger(__name__) not print |
| Async | No blocking IO in async def routes |
| Money | Decimal or integer cents |
# pyproject.toml excerpt
[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B", "SIM"]
ignore = ["E501"] # if formatter handles line lengthuv sync pins tool versions.# type: ignore[arg-type] # BILL-99.0.1 + 0.2 bugs. Fix: Decimal or int cents.except: - Masks KeyboardInterrupt. Fix: catch Exception minimum, preferably specific types.| Alternative | Use When | Don't Use When |
|---|---|---|
| Org-wide python-rules doc | Cross-team standards | Service-specific overrides needed |
| Automated ruff only | Small team | Onboarding needs prose examples |
| Google Python style guide | External reference | Conflicts with ruff config |
| No style guide | Never | Reviews bikeshed forever |
ruff format when ruff adopted - one tool; do not run both.
ruff formatter picks consistently - do not hand-fight in review.
Public API and non-obvious locals - not name = "ada" in small functions.
Public modules/classes/functions yes - Google or numpy style per README.
Pick one in pyproject.toml - match formatter and reviewer expectations.
Absolute from billing.domain import models in apps - relative only within tight package per ADR.
StrEnum or Literal for small closed sets - document in type-hints section.
test_<behavior>_when_<condition> - readable failure output.
feat, fix, chore, docs, refactor, test - match changelog automation if any.
ADR or inline comment with reason - not silent one-off in single PR.
Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.
Reviewed by Chris St. John·Last updated Jul 16, 2026