audit-labs/audit-tools
A collection of scripts, queries, and other goodies you can use in an audit.
clone: git clone https://gitbay.org/audit-labs/audit-tools.git
main: sampling/sampling_tool/reporting.py · raw
1"""Human-readable reporting outputs."""
2
3from __future__ import annotations
4
5from pathlib import Path
6
7
8class RunLogger:
9 def __init__(self) -> None:
10 self.lines: list[str] = []
11
12 def log(self, message: str) -> None:
13 self.lines.append(message)
14
15 def warning(self, message: str) -> None:
16 self.log(f"WARNING: {message}")
17
18 def error(self, message: str) -> None:
19 self.log(f"ERROR: {message}")
20
21 def write(self, path: Path) -> None:
22 path.write_text("\n".join(self.lines) + "\n")
23
24
25def build_methodology(
26 *,
27 input_file: Path,
28 input_sheet: str | None,
29 input_sha256: str,
30 source_row_count: int,
31 options,
32 effective_id_column: str | None,
33 id_column_omitted: bool,
34 duplicate_id_count: int,
35 blank_id_count: int,
36 sample_size_actual: int,
37 random_seed: int | None,
38 strata_summary: list[dict[str, object]] | None,
39) -> str:
40 lines = [
41 "Audit Sampling Methodology",
42 "",
43 f"Source file: {input_file}",
44 f"Source sheet: {input_sheet or ''}",
45 f"Input SHA-256: {input_sha256}",
46 f"Source row count: {source_row_count}",
47 ]
48 if id_column_omitted:
49 lines.append(
50 "ID column: omitted; _audit_row_id was generated from _source_row_number."
51 )
52 else:
53 lines.append(f"ID column: {options.id_column}")
54 lines.extend(
55 [
56 f"Effective ID column: {effective_id_column or ''}",
57 f"Duplicate ID rows identified: {duplicate_id_count}",
58 f"Blank ID rows identified: {blank_id_count}",
59 f"Blank ID handling: {'excluded' if options.exclude_blank_id else 'retained'}",
60 f"Filters applied: {options.filters or {}}",
61 f"Sampling method: {options.method}",
62 f"Sample size requested: {options.sample_size or ''}",
63 f"Sample size selected: {sample_size_actual}",
64 f"Random seed used: {random_seed or ''}",
65 ]
66 )
67 if options.method == "stratified":
68 lines.append(f"Stratification column: {options.stratify_column}")
69 lines.append(f"Strata counts: {options.strata_counts or ''}")
70 lines.append(f"Strata proportions: {options.strata_proportions or ''}")
71 if strata_summary:
72 lines.append("Strata summary:")
73 for row in strata_summary:
74 lines.append(
75 " "
76 f"{row['Stratum']}: population={row['Population Count']}, "
77 f"requested={row['Requested Sample Count']}, "
78 f"actual={row['Actual Sample Count']}, "
79 f"shortfall={row['Shortfall']}"
80 )
81 lines.extend(
82 [
83 "Sampling was performed without replacement.",
84 "Selected rows retain source row numbers and original source fields.",
85 ]
86 )
87 return "\n".join(lines) + "\n"