Typowanie statyczne i mypy

Python jest dynamiczny, ale w ZEUS-ie traktujemy adnotacje typów jak obowiązkowy kontrakt. Typy wyłapują błędy, zanim trafią na produkcję, dokumentują API funkcji i pozwalają IDE podpowiadać sensownie. Sprawdza je mypy — w trybie strict.

Podstawowe adnotacje

def normalize_forest(name: str) -> str:
    return name.strip().lower()


async def fetch_hosts(forest: str, limit: int = 100) -> list[str]:
    ...

Od Pythona 3.9+ używamy wbudowanych generyków (list[str], dict[str, int]), a nie List/Dict z typing. Od 3.10+ unie zapisujemy przez |.

# starym stylem (nie używaj)
from typing import List, Optional
def f(x: Optional[int]) -> List[str]: ...

# nasz styl
def f(x: int | None) -> list[str]: ...

Optional, None i Pydantic

X | None to typ, który może być None. mypy zmusi cię do obsłużenia tego przypadku — i o to chodzi.

def get_probe(probe_id: str) -> Probe | None:
    return repo.find(probe_id)


probe = get_probe(pid)
print(probe.host)        # mypy: error — probe może być None
if probe is not None:
    print(probe.host)    # OK — zawężenie typu (narrowing)

Typowanie funkcji asynchronicznych i ARQ

W zadaniach ARQ i handlerach FastAPI typujemy zarówno argumenty, jak i zwrot:

async def enqueue_scan(ctx: dict[str, Any], forest: str) -> int:
    job = await ctx["redis"].enqueue_job("run_scan", forest)
    return await job.result()

Standard ProfessNet — strict mypy

[tool.mypy]
python_version = "3.12"
strict = true
warn_unused_ignores = true
disallow_untyped_defs = true
plugins = ["pydantic.mypy"]

Standard ProfessNet: nowy kod pisze się w strict = true. Plugin pydantic.mypy rozumie modele Pydantic i waliduje pola.

Any to dług techniczny

Any wyłącza sprawdzanie typów — używaj go świadomie i rzadko. Gdy musisz tymczasowo wyciszyć błąd, dodaj komentarz z powodem:

data = parse(raw)  # type: ignore[no-any-return]  # zewn. lib bez stubów
KonstrukcjaKiedy
`XNone`
Sequence[X]argument tylko-do-odczytu (lista lub krotka)
Protocolkontrakt zachowania bez dziedziczenia
TypedDictsłownik o znanych kluczach (np. payload JSON)
Anyostateczność, zawsze z komentarzem

Uruchamianie

mypy app/

mypy odpalamy w CI obok ruff i black. Czerwone mypy = PR zablokowany.

Wskazówka: jeśli biblioteka nie ma typów, doinstaluj paczkę types-... (np. types-requests) zamiast zasypywać kod type: ignore.


Typowanie kosztuje minutę przy pisaniu, a oszczędza godziny debugowania na produkcji. W ZEUS-ie typowany, sprawdzony przez mypy kod to warunek wejścia do głównej gałęzi.