forked from ChelseaKR/tods-validate
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild_conformance_corpus.py
More file actions
76 lines (59 loc) · 2.84 KB
/
Copy pathbuild_conformance_corpus.py
File metadata and controls
76 lines (59 loc) · 2.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#!/usr/bin/env python3
"""Build the downloadable TODS conformance corpus from tests/fixtures.
The corpus is a single zip containing every per-rule invalid fixture and the
valid feed, plus an ``expectations.json`` mapping each fixture to the rule IDs
it should produce. A TODS producer (or another validator author) can run the
fixtures through their tooling and check the rule IDs against expectations,
turning this project's test corpus into a shared, versioned conformance suite.
Usage: python scripts/build_conformance_corpus.py [OUTPUT.zip]
"""
from __future__ import annotations
import json
import sys
import zipfile
from pathlib import Path
from tods_validate.rules import CATEGORIES
from tods_validate.runner import run
_ROOT = Path(__file__).resolve().parent.parent
_FIXTURES = _ROOT / "tests" / "fixtures"
_ALL_CATEGORIES = frozenset(CATEGORIES)
def _rule_ids(path: Path, gtfs: Path | None = None) -> list[str]:
_, findings = run(path, gtfs, enabled=_ALL_CATEGORIES)
return sorted({f.rule_id for f in findings})
def build(out: Path) -> dict[str, list[str]]:
"""Write the corpus zip to ``out`` and return the expectations mapping."""
expectations: dict[str, list[str]] = {}
members: list[tuple[str, Path]] = []
for fixture in sorted((_FIXTURES / "invalid").iterdir()):
if not fixture.is_dir():
continue
expectations[f"invalid/{fixture.name}"] = _rule_ids(fixture)
for file in sorted(fixture.iterdir()):
if file.is_file():
members.append((f"invalid/{fixture.name}/{file.name}", file))
valid_tods, valid_gtfs = _FIXTURES / "valid" / "tods", _FIXTURES / "valid" / "gtfs"
expectations["valid"] = _rule_ids(valid_tods, valid_gtfs)
for sub in ("tods", "gtfs"):
for file in sorted((_FIXTURES / "valid" / sub).iterdir()):
if file.is_file():
members.append((f"valid/{sub}/{file.name}", file))
out.parent.mkdir(parents=True, exist_ok=True)
with zipfile.ZipFile(out, "w", compression=zipfile.ZIP_DEFLATED) as zf:
for arcname, file in members:
zf.write(file, arcname)
zf.writestr("expectations.json", json.dumps(expectations, indent=2, sort_keys=True))
zf.writestr(
"README.md",
"# TODS conformance corpus\n\n"
"Each `invalid/<RULE-ID>/` directory is a minimal feed that should produce "
"that rule; `valid/` should produce nothing. `expectations.json` maps each "
"fixture to its expected rule IDs. Built from tods-validate with all opt-in "
"categories enabled.\n",
)
return expectations
def main() -> None:
out = Path(sys.argv[1]) if len(sys.argv) > 1 else _ROOT / "dist" / "tods-conformance-corpus.zip"
expectations = build(out)
print(f"wrote {out} ({len(expectations)} fixtures)")
if __name__ == "__main__":
main()