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).

class otto.coverage.store.model.LineHits(counts=<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 : --is-rst--:py:class:`dict`\ \[:py:class:`str`, :py:class:`int`]
add(tier, n)

Add n hits to tier.

Return type:

None

for_tier(tier)

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

Return type:

int

total()

Sum of hits across all tiers.

Return type:

int

is_hit(tier=None)

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

Return type:

bool

merge(other)

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

Return type:

None

to_dict()
Return type:

dict[str, int]

class otto.coverage.store.model.BranchHits(block, branch, hits=<factory>, reachable=<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 : --is-rst--:py:class:`int`
branch : --is-rst--:py:class:`int`
hits : --is-rst--:py:class:`~otto.coverage.store.model.LineHits`
reachable : --is-rst--:py:class:`dict`\ \[:py:class:`str`, :py:class:`bool`]
property branch_id : tuple[int, int]
set_reachable(tier, reachable)

Record a reachability observation for tier.

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

Return type:

None

is_reachable(tier=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).

Return type:

bool | None

is_hit_for(tier=None)

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

Return type:

bool

merge(other)
Return type:

None

to_dict()
Return type:

dict[str, Any]

class otto.coverage.store.model.LineRecord(line_number, hits=<factory>, branches=<factory>, commit_hash=None, commit_author=None, commit_summary=None)

Bases: object

Coverage data for a single source line.

line_number : --is-rst--:py:class:`int`
hits : --is-rst--:py:class:`~otto.coverage.store.model.LineHits`
branches : --is-rst--:py:class:`list`\ \[:py:class:`~otto.coverage.store.model.BranchHits`]
commit_hash : --is-rst--:py:class:`str` | :py:obj:`None` = None
commit_author : --is-rst--:py:class:`str` | :py:obj:`None` = None
commit_summary : --is-rst--:py:class:`str` | :py:obj:`None` = None
merge(other)
Return type:

None

class otto.coverage.store.model.FileRecord(path, lines=<factory>)

Bases: object

Coverage data for a single source file.

path : --is-rst--:py:class:`~pathlib.Path`
lines : --is-rst--:py:class:`dict`\ \[:py:class:`int`, :py:class:`~otto.coverage.store.model.LineRecord`]
get_or_create_line(line_number)
Return type:

LineRecord

merge(other)
Return type:

None

line_coverage_pct(tier=None)

Line coverage percentage, optionally filtered by tier.

Return type:

float

branch_coverage_pct(tier=None, conservative=True)

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.

Return type:

float

sorted_lines()
Return type:

Iterator[LineRecord]

to_dict()
Return type:

dict[str, Any]

class otto.coverage.store.model.CoverageStore(tier_order=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)

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.

Return type:

None

get_or_create_file(path)
Return type:

FileRecord

merge_file(record)
Return type:

None

files()
Return type:

Iterator[FileRecord]

file_count()
Return type:

int

overall_pct(tier=None)

Overall line coverage percentage across all files.

Return type:

float

overall_branch_pct(tier=None, conservative=True)

Overall branch coverage percentage across all files.

Return type:

float

save(path)

Serialise the store to JSON.

Return type:

None

classmethod load(path)

Deserialise a store from JSON.

Return type:

CoverageStore