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

1"""Concise terminal rendering for ``secchi show``.""" 

2 

3from __future__ import annotations 

4 

5from secchi.models import DerivedPackageData, PackageInfo 

6 

7 

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 ) 

29 

30 

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)