from __future__ import annotations from dataclasses import dataclass, field from .probe import Result @dataclass class PhaseStats: min_ms: float = 0.0 avg_ms: float = 0.0 max_ms: float = 0.0 present: bool = False @dataclass class Aggregate: url: str = "" count: int = 0 status_code: int = 0 dns: PhaseStats = field(default_factory=PhaseStats) connect: PhaseStats = field(default_factory=PhaseStats) tls: PhaseStats = field(default_factory=PhaseStats) ttfb: PhaseStats = field(default_factory=PhaseStats) transfer: PhaseStats = field(default_factory=PhaseStats) total: PhaseStats = field(default_factory=PhaseStats) def summarize(results: list[Result]) -> Aggregate: """Compute per-phase min/avg/max over a list of succeeded Results.""" if not results: return Aggregate() a = Aggregate(url=results[0].url, count=len(results)) a.status_code = results[-1].status_code def _stats(attr: str) -> PhaseStats: vals = [getattr(r, attr).ms for r in results if getattr(r, attr).present] if not vals: return PhaseStats() return PhaseStats( min_ms=min(vals), avg_ms=sum(vals) / len(vals), max_ms=max(vals), present=True, ) a.dns = _stats("dns") a.connect = _stats("connect") a.tls = _stats("tls") a.ttfb = _stats("ttfb") a.transfer = _stats("transfer") a.total = _stats("total") return a