Coverage for src/secchi/renderers/summary.py: 88%
17 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-08-04 22:15 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-08-04 22:15 +0000
1"""Concise terminal rendering for ``secchi show``."""
3from __future__ import annotations
5from secchi.models import DerivedPackageData, PackageInfo
8def render_summary(info: PackageInfo, derived: DerivedPackageData) -> str:
9 change = derived.downloads_30d_pct_change
10 adoption = (
11 "—" if change is None else f"{'▲' if change >= 0 else '▼'} {abs(change):.1f}%"
12 )
13 stars = (
14 _format_count(info.github_stats.stars) if info.github_stats.resolved else "—"
15 )
16 dependents = _format_count(info.reverse_dependency_count)
17 health = derived.health_score.total
18 return "\n".join(
19 [
20 info.name,
21 "─" * max(20, len(info.name)),
22 f"Health Score {health} / 100",
23 f"Latest Version {info.latest_version or '—'}",
24 f"Downloads {adoption}",
25 f"GitHub Stars {stars}",
26 f"Dependents {dependents}",
27 ]
28 )
31def _format_count(value: int | None) -> str:
32 if value is None:
33 return "—"
34 if value >= 1_000_000:
35 return f"{value / 1_000_000:.1f}M"
36 if value >= 1_000:
37 return f"{value / 1_000:.1f}k"
38 return str(value)