docassert 0.4.0__tar.gz → 0.5.0__tar.gz
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.
- {docassert-0.4.0/docassert.egg-info → docassert-0.5.0}/PKG-INFO +14 -3
- {docassert-0.4.0 → docassert-0.5.0}/README.md +13 -2
- {docassert-0.4.0 → docassert-0.5.0}/docassert/__init__.py +1 -1
- {docassert-0.4.0 → docassert-0.5.0}/docassert/cli.py +6 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/report.py +27 -1
- {docassert-0.4.0 → docassert-0.5.0/docassert.egg-info}/PKG-INFO +14 -3
- {docassert-0.4.0 → docassert-0.5.0}/docassert.egg-info/SOURCES.txt +1 -0
- {docassert-0.4.0 → docassert-0.5.0}/tests/test_extract.py +32 -0
- docassert-0.5.0/tests/test_json_report.py +43 -0
- {docassert-0.4.0 → docassert-0.5.0}/LICENSE +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/NOTICE +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/__main__.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/consistency.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/criteria/adr.criteria.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/criteria/benefits-realization.criteria.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/criteria/brd.criteria.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/criteria/business-case.criteria.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/criteria/charter.criteria.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/criteria/data-migration-plan.criteria.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/criteria/frnfr.criteria.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/criteria/hypercare-plan.criteria.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/criteria/post-implementation-review.criteria.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/criteria/prd.criteria.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/criteria/project.criteria.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/criteria/qa-test-plan.criteria.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/criteria/raci-stakeholder.criteria.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/criteria/release-cutover-plan.criteria.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/criteria/risk-register.criteria.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/criteria/rollback-plan.criteria.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/criteria/runbook.criteria.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/criteria/status-report.criteria.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/criteria/test-cases.criteria.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/criteria/user-story.criteria.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/profiles/agile-delivery.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/profiles/lean-startup.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/profiles/regulated-industry.yaml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/schema/adr.schema.json +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/schema/benefits-realization.schema.json +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/schema/brd.schema.json +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/schema/business-case.schema.json +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/schema/charter.schema.json +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/schema/data-migration-plan.schema.json +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/schema/frnfr.schema.json +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/schema/hypercare-plan.schema.json +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/schema/post-implementation-review.schema.json +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/schema/prd.schema.json +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/schema/project.schema.json +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/schema/qa-test-plan.schema.json +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/schema/raci-stakeholder.schema.json +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/schema/release-cutover-plan.schema.json +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/schema/risk-register.schema.json +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/schema/rollback-plan.schema.json +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/schema/runbook.schema.json +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/schema/status-report.schema.json +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/schema/test-cases.schema.json +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/schema/user-story.schema.json +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/skills/doc-to-pmo/SKILL.md +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/adr.template.md +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/benefits-realization.template.md +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/brd.template.md +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/business-case.template.md +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/charter.template.md +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/data-migration-plan.template.md +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/frnfr.template.md +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/hypercare-plan.template.md +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/post-implementation-review.template.md +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/prd.template.md +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/project.template.md +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/qa-test-plan.template.md +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/raci-stakeholder.template.md +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/release-cutover-plan.template.md +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/risk-register.template.md +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/rollback-plan.template.md +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/runbook.template.md +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/status-report.template.md +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/test-cases.template.md +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/user-story.template.md +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/config.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/consistency.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/extract.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/graph.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/loader.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/models.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/profiles.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/projects.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/rtm.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/scaffold.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/semantic.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/status.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert/structural.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert.egg-info/dependency_links.txt +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert.egg-info/entry_points.txt +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert.egg-info/requires.txt +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/docassert.egg-info/top_level.txt +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/pyproject.toml +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/setup.cfg +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/tests/test_config.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/tests/test_consistency.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/tests/test_defects.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/tests/test_graph.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/tests/test_kinds_delivery.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/tests/test_kinds_governance.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/tests/test_kinds_operate.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/tests/test_kinds_reporting.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/tests/test_profiles.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/tests/test_projects.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/tests/test_scaffold.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/tests/test_status.py +0 -0
- {docassert-0.4.0 → docassert-0.5.0}/tests/test_structural.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: docassert
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Unit testing for business documents — validate structured Markdown docs against a configurable audit standard.
|
|
5
5
|
Author: C4G Enterprises Inc.
|
|
6
6
|
License: Apache-2.0
|
|
@@ -85,8 +85,8 @@ flagged as TODOs, never invented). The skill's source is
|
|
|
85
85
|
|
|
86
86
|
| Command | What it does |
|
|
87
87
|
|---|---|
|
|
88
|
-
| `docassert validate <globs>` | Validate documents against their kind's criteria. Exit code = number of blocking failures (capped at 125). |
|
|
89
|
-
| `docassert consistency` | Cross-document checks: referential integrity, coverage, required links, profile completeness. |
|
|
88
|
+
| `docassert validate <globs>` | Validate documents against their kind's criteria. Exit code = number of blocking failures (capped at 125). Reports: `--junit` / `--markdown` / `--json`. |
|
|
89
|
+
| `docassert consistency` | Cross-document checks: referential integrity, coverage, required links, profile completeness. Reports: `--junit` / `--markdown` / `--json`. |
|
|
90
90
|
| `docassert rtm [--project ID]` | Requirements traceability matrix (Markdown or CSV). |
|
|
91
91
|
| `docassert status [--project ID] [--index]` | Derived project status (md / json / html). |
|
|
92
92
|
| `docassert pages --out DIR` | Build the portfolio site (index + a page per project). |
|
|
@@ -117,6 +117,17 @@ kind is adding a trio — no code for the common cases.
|
|
|
117
117
|
- **Semantic — AI-graded, advisory.** Scored via the Anthropic API and posted to
|
|
118
118
|
the PR — never blocking. Set `ANTHROPIC_API_KEY` to enable; skipped otherwise.
|
|
119
119
|
|
|
120
|
+
## Privacy
|
|
121
|
+
|
|
122
|
+
Structural checks run **entirely locally** — no document content leaves your
|
|
123
|
+
machine or CI runner. Semantic checks are the one exception: when
|
|
124
|
+
`ANTHROPIC_API_KEY` is set, the graded excerpts (section text, linked item
|
|
125
|
+
text) are sent to the **Anthropic API** for scoring. Without the key, semantic
|
|
126
|
+
checks are skipped and nothing is sent anywhere. Alignment grading is capped at
|
|
127
|
+
`alignment_limit` links per run (default 25). If your documents are
|
|
128
|
+
confidential, run without the key or review [Anthropic's data-usage
|
|
129
|
+
policies](https://www.anthropic.com/legal/commercial-terms) first.
|
|
130
|
+
|
|
120
131
|
## Development
|
|
121
132
|
|
|
122
133
|
```bash
|
|
@@ -47,8 +47,8 @@ flagged as TODOs, never invented). The skill's source is
|
|
|
47
47
|
|
|
48
48
|
| Command | What it does |
|
|
49
49
|
|---|---|
|
|
50
|
-
| `docassert validate <globs>` | Validate documents against their kind's criteria. Exit code = number of blocking failures (capped at 125). |
|
|
51
|
-
| `docassert consistency` | Cross-document checks: referential integrity, coverage, required links, profile completeness. |
|
|
50
|
+
| `docassert validate <globs>` | Validate documents against their kind's criteria. Exit code = number of blocking failures (capped at 125). Reports: `--junit` / `--markdown` / `--json`. |
|
|
51
|
+
| `docassert consistency` | Cross-document checks: referential integrity, coverage, required links, profile completeness. Reports: `--junit` / `--markdown` / `--json`. |
|
|
52
52
|
| `docassert rtm [--project ID]` | Requirements traceability matrix (Markdown or CSV). |
|
|
53
53
|
| `docassert status [--project ID] [--index]` | Derived project status (md / json / html). |
|
|
54
54
|
| `docassert pages --out DIR` | Build the portfolio site (index + a page per project). |
|
|
@@ -79,6 +79,17 @@ kind is adding a trio — no code for the common cases.
|
|
|
79
79
|
- **Semantic — AI-graded, advisory.** Scored via the Anthropic API and posted to
|
|
80
80
|
the PR — never blocking. Set `ANTHROPIC_API_KEY` to enable; skipped otherwise.
|
|
81
81
|
|
|
82
|
+
## Privacy
|
|
83
|
+
|
|
84
|
+
Structural checks run **entirely locally** — no document content leaves your
|
|
85
|
+
machine or CI runner. Semantic checks are the one exception: when
|
|
86
|
+
`ANTHROPIC_API_KEY` is set, the graded excerpts (section text, linked item
|
|
87
|
+
text) are sent to the **Anthropic API** for scoring. Without the key, semantic
|
|
88
|
+
checks are skipped and nothing is sent anywhere. Alignment grading is capped at
|
|
89
|
+
`alignment_limit` links per run (default 25). If your documents are
|
|
90
|
+
confidential, run without the key or review [Anthropic's data-usage
|
|
91
|
+
policies](https://www.anthropic.com/legal/commercial-terms) first.
|
|
92
|
+
|
|
82
93
|
## Development
|
|
83
94
|
|
|
84
95
|
```bash
|
|
@@ -116,6 +116,8 @@ def cmd_validate(args: argparse.Namespace) -> int:
|
|
|
116
116
|
Path(args.junit).write_text(report.junit(results_by_doc))
|
|
117
117
|
if args.markdown:
|
|
118
118
|
Path(args.markdown).write_text(report.markdown(results_by_doc))
|
|
119
|
+
if args.json:
|
|
120
|
+
Path(args.json).write_text(report.json_report(results_by_doc))
|
|
119
121
|
|
|
120
122
|
return _capped(sum(1 for rs in results_by_doc.values()
|
|
121
123
|
for r in rs if r.is_blocking_failure))
|
|
@@ -133,6 +135,8 @@ def cmd_consistency(args: argparse.Namespace) -> int:
|
|
|
133
135
|
if args.markdown:
|
|
134
136
|
Path(args.markdown).write_text(
|
|
135
137
|
report.markdown(results_by_doc, title="docassert consistency"))
|
|
138
|
+
if args.json:
|
|
139
|
+
Path(args.json).write_text(report.json_report(results_by_doc))
|
|
136
140
|
|
|
137
141
|
return _capped(sum(1 for r in results if r.is_blocking_failure))
|
|
138
142
|
|
|
@@ -292,12 +296,14 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
292
296
|
v.add_argument("paths", nargs="+", help="Markdown files or globs.")
|
|
293
297
|
v.add_argument("--junit", help="Write a JUnit XML report to this path.")
|
|
294
298
|
v.add_argument("--markdown", help="Write a PR-comment markdown report to this path.")
|
|
299
|
+
v.add_argument("--json", help="Write a machine-readable JSON report to this path.")
|
|
295
300
|
docs_dir_opt(v)
|
|
296
301
|
v.set_defaults(func=cmd_validate)
|
|
297
302
|
|
|
298
303
|
c = sub.add_parser("consistency", help="Check cross-document traceability.")
|
|
299
304
|
c.add_argument("--junit", help="Write a JUnit XML report to this path.")
|
|
300
305
|
c.add_argument("--markdown", help="Write a PR-comment markdown report to this path.")
|
|
306
|
+
c.add_argument("--json", help="Write a machine-readable JSON report to this path.")
|
|
301
307
|
c.add_argument("--no-semantic", action="store_true",
|
|
302
308
|
help="Skip AI alignment (structural consistency only).")
|
|
303
309
|
docs_dir_opt(c)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
"""Render check results as console text, PR-comment markdown,
|
|
1
|
+
"""Render check results as console text, PR-comment markdown, JUnit XML, or JSON."""
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
|
+
import json as _json
|
|
4
5
|
import xml.etree.ElementTree as ET
|
|
5
6
|
from xml.dom import minidom
|
|
6
7
|
|
|
@@ -37,6 +38,31 @@ def summary_line(results_by_doc: dict[str, list[CheckResult]]) -> str:
|
|
|
37
38
|
return f"{_TICK} All structural checks passed across {docs} document(s) {_DASH} clear to merge."
|
|
38
39
|
|
|
39
40
|
|
|
41
|
+
def json_report(results_by_doc: dict[str, list[CheckResult]]) -> str:
|
|
42
|
+
"""Machine-readable results: one entry per document, plus a summary."""
|
|
43
|
+
documents = {
|
|
44
|
+
path: [{
|
|
45
|
+
"check_id": r.check_id,
|
|
46
|
+
"passed": r.passed,
|
|
47
|
+
"blocking": r.blocking,
|
|
48
|
+
"kind": r.kind,
|
|
49
|
+
"score": r.score,
|
|
50
|
+
"detail": r.detail,
|
|
51
|
+
} for r in results]
|
|
52
|
+
for path, results in results_by_doc.items()
|
|
53
|
+
}
|
|
54
|
+
all_results = [r for rs in results_by_doc.values() for r in rs]
|
|
55
|
+
summary = {
|
|
56
|
+
"documents": len(results_by_doc),
|
|
57
|
+
"checks": len(all_results),
|
|
58
|
+
"blocking_failures": sum(1 for r in all_results if r.is_blocking_failure),
|
|
59
|
+
"advisory_failures": sum(1 for r in all_results
|
|
60
|
+
if not r.passed and not r.blocking),
|
|
61
|
+
"passed": not any(r.is_blocking_failure for r in all_results),
|
|
62
|
+
}
|
|
63
|
+
return _json.dumps({"summary": summary, "documents": documents}, indent=2) + "\n"
|
|
64
|
+
|
|
65
|
+
|
|
40
66
|
def markdown(results_by_doc: dict[str, list[CheckResult]],
|
|
41
67
|
title: str = "docassert audit") -> str:
|
|
42
68
|
"""PR-comment body."""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: docassert
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Unit testing for business documents — validate structured Markdown docs against a configurable audit standard.
|
|
5
5
|
Author: C4G Enterprises Inc.
|
|
6
6
|
License: Apache-2.0
|
|
@@ -85,8 +85,8 @@ flagged as TODOs, never invented). The skill's source is
|
|
|
85
85
|
|
|
86
86
|
| Command | What it does |
|
|
87
87
|
|---|---|
|
|
88
|
-
| `docassert validate <globs>` | Validate documents against their kind's criteria. Exit code = number of blocking failures (capped at 125). |
|
|
89
|
-
| `docassert consistency` | Cross-document checks: referential integrity, coverage, required links, profile completeness. |
|
|
88
|
+
| `docassert validate <globs>` | Validate documents against their kind's criteria. Exit code = number of blocking failures (capped at 125). Reports: `--junit` / `--markdown` / `--json`. |
|
|
89
|
+
| `docassert consistency` | Cross-document checks: referential integrity, coverage, required links, profile completeness. Reports: `--junit` / `--markdown` / `--json`. |
|
|
90
90
|
| `docassert rtm [--project ID]` | Requirements traceability matrix (Markdown or CSV). |
|
|
91
91
|
| `docassert status [--project ID] [--index]` | Derived project status (md / json / html). |
|
|
92
92
|
| `docassert pages --out DIR` | Build the portfolio site (index + a page per project). |
|
|
@@ -117,6 +117,17 @@ kind is adding a trio — no code for the common cases.
|
|
|
117
117
|
- **Semantic — AI-graded, advisory.** Scored via the Anthropic API and posted to
|
|
118
118
|
the PR — never blocking. Set `ANTHROPIC_API_KEY` to enable; skipped otherwise.
|
|
119
119
|
|
|
120
|
+
## Privacy
|
|
121
|
+
|
|
122
|
+
Structural checks run **entirely locally** — no document content leaves your
|
|
123
|
+
machine or CI runner. Semantic checks are the one exception: when
|
|
124
|
+
`ANTHROPIC_API_KEY` is set, the graded excerpts (section text, linked item
|
|
125
|
+
text) are sent to the **Anthropic API** for scoring. Without the key, semantic
|
|
126
|
+
checks are skipped and nothing is sent anywhere. Alignment grading is capped at
|
|
127
|
+
`alignment_limit` links per run (default 25). If your documents are
|
|
128
|
+
confidential, run without the key or review [Anthropic's data-usage
|
|
129
|
+
policies](https://www.anthropic.com/legal/commercial-terms) first.
|
|
130
|
+
|
|
120
131
|
## Development
|
|
121
132
|
|
|
122
133
|
```bash
|
|
@@ -30,6 +30,38 @@ def test_unsupported_type_raises(tmp_path):
|
|
|
30
30
|
E.extract(f)
|
|
31
31
|
|
|
32
32
|
|
|
33
|
+
def _minimal_pdf(text: str) -> bytes:
|
|
34
|
+
"""Assemble a one-page PDF with `text` in a content stream, xref included."""
|
|
35
|
+
stream = f"BT /F1 24 Tf 72 720 Td ({text}) Tj ET".encode()
|
|
36
|
+
objects = [
|
|
37
|
+
b"<< /Type /Catalog /Pages 2 0 R >>",
|
|
38
|
+
b"<< /Type /Pages /Kids [3 0 R] /Count 1 >>",
|
|
39
|
+
(b"<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] "
|
|
40
|
+
b"/Contents 4 0 R /Resources << /Font << /F1 5 0 R >> >> >>"),
|
|
41
|
+
b"<< /Length " + str(len(stream)).encode() + b" >>\nstream\n" + stream + b"\nendstream",
|
|
42
|
+
b"<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>",
|
|
43
|
+
]
|
|
44
|
+
out = b"%PDF-1.4\n"
|
|
45
|
+
offsets = []
|
|
46
|
+
for i, body in enumerate(objects, start=1):
|
|
47
|
+
offsets.append(len(out))
|
|
48
|
+
out += f"{i} 0 obj\n".encode() + body + b"\nendobj\n"
|
|
49
|
+
xref_at = len(out)
|
|
50
|
+
out += f"xref\n0 {len(objects) + 1}\n0000000000 65535 f \n".encode()
|
|
51
|
+
for off in offsets:
|
|
52
|
+
out += f"{off:010d} 00000 n \n".encode()
|
|
53
|
+
out += (f"trailer\n<< /Size {len(objects) + 1} /Root 1 0 R >>\n"
|
|
54
|
+
f"startxref\n{xref_at}\n%%EOF\n").encode()
|
|
55
|
+
return out
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def test_extract_pdf(tmp_path):
|
|
59
|
+
pytest.importorskip("pypdf") # needs the 'convert' extra
|
|
60
|
+
path = tmp_path / "s.pdf"
|
|
61
|
+
path.write_bytes(_minimal_pdf("Hello docassert PDF"))
|
|
62
|
+
assert "Hello docassert PDF" in E.extract(path)
|
|
63
|
+
|
|
64
|
+
|
|
33
65
|
def test_extract_docx_paragraphs_and_tables(tmp_path):
|
|
34
66
|
docx = pytest.importorskip("docx") # needs the 'convert' extra
|
|
35
67
|
d = docx.Document()
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Tests for the machine-readable JSON report (`--json`)."""
|
|
2
|
+
import json
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from docassert import report
|
|
6
|
+
from docassert.cli import main
|
|
7
|
+
from docassert.models import CheckResult
|
|
8
|
+
|
|
9
|
+
ROOT = Path(__file__).resolve().parent.parent
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_json_report_shape():
|
|
13
|
+
results = {
|
|
14
|
+
"a.md": [CheckResult("c1", True, True, "ok"),
|
|
15
|
+
CheckResult("c2", False, True, "bad")],
|
|
16
|
+
"b.md": [CheckResult("c3", False, False, "meh", kind="semantic", score=0.4)],
|
|
17
|
+
}
|
|
18
|
+
data = json.loads(report.json_report(results))
|
|
19
|
+
assert data["summary"] == {"documents": 2, "checks": 3, "blocking_failures": 1,
|
|
20
|
+
"advisory_failures": 1, "passed": False}
|
|
21
|
+
assert data["documents"]["a.md"][1]["check_id"] == "c2"
|
|
22
|
+
assert data["documents"]["b.md"][0]["score"] == 0.4
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_cli_validate_writes_json(tmp_path, monkeypatch):
|
|
26
|
+
monkeypatch.chdir(ROOT) # criteria/schema resolve; sample documents exist
|
|
27
|
+
out = tmp_path / "r.json"
|
|
28
|
+
code = main(["validate", "documents/PRJ-001-AUR/charter.md", "--json", str(out)])
|
|
29
|
+
assert code == 0
|
|
30
|
+
data = json.loads(out.read_text())
|
|
31
|
+
assert data["summary"]["passed"] is True
|
|
32
|
+
assert "documents/PRJ-001-AUR/charter.md" in data["documents"]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_cli_consistency_writes_json(tmp_path, monkeypatch):
|
|
36
|
+
monkeypatch.chdir(ROOT)
|
|
37
|
+
monkeypatch.delenv("ANTHROPIC_API_KEY", raising=False)
|
|
38
|
+
out = tmp_path / "c.json"
|
|
39
|
+
code = main(["consistency", "--no-semantic", "--json", str(out)])
|
|
40
|
+
assert code == 0
|
|
41
|
+
data = json.loads(out.read_text())
|
|
42
|
+
checks = {c["check_id"] for c in data["documents"]["consistency (cross-document)"]}
|
|
43
|
+
assert {"item-id-uniqueness", "referential-integrity", "coverage"} <= checks
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.4.0 → docassert-0.5.0}/docassert/_data/criteria/benefits-realization.criteria.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.4.0 → docassert-0.5.0}/docassert/_data/criteria/data-migration-plan.criteria.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.4.0 → docassert-0.5.0}/docassert/_data/criteria/release-cutover-plan.criteria.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.4.0 → docassert-0.5.0}/docassert/_data/schema/post-implementation-review.schema.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/benefits-realization.template.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/data-migration-plan.template.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/post-implementation-review.template.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.4.0 → docassert-0.5.0}/docassert/_data/templates/release-cutover-plan.template.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|