coverage.store.model

Coverage data model.

This is the core of the coverage module — everything else feeds into or reads from these types. The model is deliberately independent of gcov, lcov, or coverage.py internals.

Coverage tiers are names — free-form strings like "system", "unit", "manual", or anything a user wires up on the command line. LineHits and BranchHits store per-tier counts in dicts keyed by tier name, so adding a new tier requires no changes to the model. A CoverageStore also carries a tier_order list that defines the precedence of tiers for presentation purposes (first = highest precedence).

otto.coverage.store.model.TIER_SYSTEM = 'system'

Conventional tier name used by the merged .gcda pipeline.

Any string is a valid tier name; this constant spares callers a string literal when they mean the canonical system-coverage tier.

class otto.coverage.store.model.LineHits(counts: dict[str, int] = <factory>)

Bases: object

Per-tier hit counts for a single line.

Counts are a dict keyed by tier name. Absent keys mean zero hits for that tier.

counts : dict[str, int]
add(tier: str, n: int) None

Add n hits to tier.

for_tier(tier: str) int

Hit count for tier (0 if the tier has no entry).

total() int

Sum of hits across all tiers.

is_hit(tier: str | None = None) bool

True if hit in tier (or in any tier when tier is None).

merge(other: LineHits) None

Additive merge — sum counts for every tier present in other.

to_dict() dict[str, int]
class otto.coverage.store.model.BranchHits(block: int, branch: int, hits: ~otto.coverage.store.model.LineHits = <factory>, reachable: dict[str, bool] = <factory>)

Bases: object

Per-tier hit counts and reachability for one branch.

Reachability is tri-state per tier:

  • key present, value True → observed as reachable at least once

  • key present, value False → observed only as unreachable (lcov -)

  • key absent → no data yet for that tier

Once a tier sees the branch as reachable it stays reachable for that tier — merges only flip FalseTrue, never the other way.

block : int
branch : int
hits : LineHits
reachable : dict[str, bool]
property branch_id : tuple[int, int]
set_reachable(tier: str, reachable: bool) None

Record a reachability observation for tier.

If the tier was already marked reachable, keep it reachable. Otherwise adopt the new value.

is_reachable(tier: str | None = None) bool | None

Reachability for tier, or combined across all tiers when None.

Returns None if no data has been recorded for the requested tier (or for any tier when tier is None).

is_hit_for(tier: str | None = None) bool

True if this branch was taken at least once in tier.

merge(other: BranchHits) None
to_dict() dict[str, Any]
class otto.coverage.store.model.LineRecord(line_number: int, hits: ~otto.coverage.store.model.LineHits = <factory>, branches: list[~otto.coverage.store.model.BranchHits] = <factory>, commit_hash: str | None = None, commit_author: str | None = None, commit_summary: str | None = None)

Bases: object

Coverage data for a single source line.

line_number : int
hits : LineHits
branches : list[BranchHits]
commit_hash : str | None = None
commit_author : str | None = None
commit_summary : str | None = None
merge(other: LineRecord) None
class otto.coverage.store.model.FileRecord(path: ~pathlib.Path, lines: dict[int, ~otto.coverage.store.model.LineRecord] = <factory>)

Bases: object

Coverage data for a single source file.

path : Path
lines : dict[int, LineRecord]
get_or_create_line(line_number: int) LineRecord
merge(other: FileRecord) None
line_coverage_pct(tier: str | None = None) float

Line coverage percentage, optionally filtered by tier.

branch_coverage_pct(tier: str | None = None, conservative: bool = True) float

Branch coverage percentage.

conservative=True (default): denominator is only branches where is_reachable(tier) is True. Matches genhtml behaviour.

conservative=False: denominator is all branches seen in any .info file.

sorted_lines() Iterator[LineRecord]
to_dict() dict[str, Any]
class otto.coverage.store.model.CoverageStore(tier_order: list[str] | None = None)

Bases: object

Central store for all coverage data across all files, hosts, and tiers.

tier_order holds the user-defined precedence of tiers — first entry is highest precedence. Downstream renderers iterate this list to drive column ordering and the winner-take-all row coloring used by the annotated source view.

register_tier(tier: str) None

Append tier to the tier order if not already present.

Loaders call this when they see a new tier so the store’s tier_order list stays in sync with the data without requiring every call site to pre-declare every tier.

get_or_create_file(path: Path) FileRecord
merge_file(record: FileRecord) None
files() Iterator[FileRecord]
file_count() int
overall_pct(tier: str | None = None) float

Overall line coverage percentage across all files.

overall_branch_pct(tier: str | None = None, conservative: bool = True) float

Overall branch coverage percentage across all files.

save(path: Path) None

Serialise the store to JSON.

classmethod load(path: Path) CoverageStore

Deserialise a store from JSON.