spreadsheet-auditor 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- spreadsheet_auditor/__init__.py +13 -0
- spreadsheet_auditor/__main__.py +8 -0
- spreadsheet_auditor/annotate.py +48 -0
- spreadsheet_auditor/audit.py +761 -0
- spreadsheet_auditor/checks/__init__.py +35 -0
- spreadsheet_auditor/checks/base.py +74 -0
- spreadsheet_auditor/checks/data_hygiene.py +24 -0
- spreadsheet_auditor/checks/finance.py +202 -0
- spreadsheet_auditor/checks/formula_integrity.py +91 -0
- spreadsheet_auditor/checks/ranges.py +58 -0
- spreadsheet_auditor/checks/reconciliation.py +32 -0
- spreadsheet_auditor/cli.py +17 -0
- spreadsheet_auditor/config_loader.py +132 -0
- spreadsheet_auditor/data_hygiene.py +115 -0
- spreadsheet_auditor/demo/__init__.py +10 -0
- spreadsheet_auditor/demo/demo_bad_budget.xlsx +0 -0
- spreadsheet_auditor/dependency_graph.py +55 -0
- spreadsheet_auditor/finding.py +136 -0
- spreadsheet_auditor/formula_drift.py +128 -0
- spreadsheet_auditor/formula_parser.py +110 -0
- spreadsheet_auditor/materiality.py +22 -0
- spreadsheet_auditor/preflight.py +53 -0
- spreadsheet_auditor/py.typed +0 -0
- spreadsheet_auditor/range_checks.py +299 -0
- spreadsheet_auditor/recalc.py +63 -0
- spreadsheet_auditor/reconcile.py +130 -0
- spreadsheet_auditor/reference_resolver.py +61 -0
- spreadsheet_auditor/report.py +399 -0
- spreadsheet_auditor/sarif.py +141 -0
- spreadsheet_auditor/suppressions.py +109 -0
- spreadsheet_auditor/workbook_inventory.py +93 -0
- spreadsheet_auditor-0.1.0.dist-info/METADATA +332 -0
- spreadsheet_auditor-0.1.0.dist-info/RECORD +37 -0
- spreadsheet_auditor-0.1.0.dist-info/WHEEL +5 -0
- spreadsheet_auditor-0.1.0.dist-info/entry_points.txt +2 -0
- spreadsheet_auditor-0.1.0.dist-info/licenses/LICENSE +21 -0
- spreadsheet_auditor-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Audit existing spreadsheets for correctness defects.
|
|
2
|
+
|
|
3
|
+
`spreadsheet-auditor` is an audit-only Agent Skill and CLI for reviewing
|
|
4
|
+
existing Excel workbooks and financial models. It identifies formula errors,
|
|
5
|
+
broken references, range mistakes, hardcoded values, reconciliation failures,
|
|
6
|
+
circular references, hidden-structure risks, and data-quality issues without
|
|
7
|
+
modifying the source workbook.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
__version__ = "0.1.0"
|
|
13
|
+
__all__ = ["__version__"]
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from openpyxl import load_workbook
|
|
6
|
+
from openpyxl.comments import Comment
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _anchor_location(location: str) -> tuple[str, str] | None:
|
|
10
|
+
"""Resolve a finding location to a single (sheet, coordinate) anchor cell.
|
|
11
|
+
|
|
12
|
+
Handles comma-joined multi-locations (uses the first) and range locations
|
|
13
|
+
(uses the top-left cell), e.g. "Sheet1!A1:B2" -> ("Sheet1", "A1").
|
|
14
|
+
"""
|
|
15
|
+
if not location:
|
|
16
|
+
return None
|
|
17
|
+
first = location.split(",", 1)[0].strip()
|
|
18
|
+
if "!" not in first:
|
|
19
|
+
return None
|
|
20
|
+
sheet_name, coord = first.split("!", 1)
|
|
21
|
+
coord = coord.split(":", 1)[0].replace("$", "").strip()
|
|
22
|
+
if not sheet_name or not coord:
|
|
23
|
+
return None
|
|
24
|
+
return sheet_name, coord
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def annotate_workbook(source_path: str | Path, output_path: str | Path, findings: list[dict]) -> None:
|
|
28
|
+
source = Path(source_path)
|
|
29
|
+
keep_vba = source.suffix.lower() == ".xlsm"
|
|
30
|
+
wb = load_workbook(source, keep_vba=keep_vba)
|
|
31
|
+
for finding in findings:
|
|
32
|
+
if finding.get("suppressed"):
|
|
33
|
+
continue
|
|
34
|
+
location = finding.get("location", "")
|
|
35
|
+
anchor = _anchor_location(location)
|
|
36
|
+
if anchor is None:
|
|
37
|
+
continue
|
|
38
|
+
sheet_name, coord = anchor
|
|
39
|
+
if sheet_name not in wb.sheetnames:
|
|
40
|
+
continue
|
|
41
|
+
cell = wb[sheet_name][coord]
|
|
42
|
+
text = (
|
|
43
|
+
f"{finding.get('severity')} {finding.get('rule_id')}\n"
|
|
44
|
+
f"{finding.get('title')}\n"
|
|
45
|
+
f"Fix: {finding.get('suggested_fix')}"
|
|
46
|
+
)
|
|
47
|
+
cell.comment = Comment(text, "Spreadsheet Auditor")
|
|
48
|
+
wb.save(output_path)
|