diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/extract_missalemeum_oracle.py | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/tools/extract_missalemeum_oracle.py b/tools/extract_missalemeum_oracle.py new file mode 100644 index 0000000..044aa54 --- /dev/null +++ b/tools/extract_missalemeum_oracle.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 +# A documented one-shot, not part of the OCaml build (spec's "no hand-written +# JSON parser" rule is about colitur's OWN sexp format -- reading someone +# else's JSON needs a reader, same reasoning as tools/bootstrap_sanctoral.ml's +# own header comment on its INI reader). Task 16: extracts the missalemeum +# oracle fixture (test/fixtures/missalemeum-ef-2026-2027.txt) that +# test/test_oracle.ml compares colitur against -- there is no JSON library in +# this project's frozen deps, so the fixture is shaped here, once, outside +# the test, exactly as test/test_differential.ml's lectio fixture already is +# (see that file's own header comment). +# +# Usage: +# python3 tools/extract_missalemeum_oracle.py <snapshot-dir> <out-file> +# +# <snapshot-dir> is ~/git/projects/lectio/sources/ already unpacked (`tar xzf +# snapshot.tar.gz` in that directory -- lectio's own scripts/snapshot- +# sources.sh does this), so <snapshot-dir>/missalemeum/en/YYYY-MM-DD.json +# exists for every day. +# +# One line per day, pipe-separated: +# date|rank|colors|title|tempora|commemorations|displaced|n_masses +# +# - rank/colors/title/tempora/commemorations/displaced are info.rank, +# info.colors (sorted, concatenated, e.g. "pv"), info.title, info.tempora +# ("-" for JSON null), the ";"-joined titles of info.commemorations and +# info.displaced ("-" for an empty list), verbatim from the JSON's own +# English strings -- not translated or slugified, so the comparator (and a +# human auditor) can match colitur's own celebration names against them. +# - n_masses is len(the day's JSON array). Four days (Christmas, All Souls) +# carry more than one Mass; entry[0]'s info block is used throughout (rank/ +# colors/tempora/commemorations/displaced are IDENTICAL across every Mass +# of the same day for all 730 days -- checked below, not assumed; see the +# task report for why entry[0] loses nothing). +# - Spaces in tempora are turned to "_" (matching the "no field has an +# internal space" convention test/fixtures/lectio-ef-2005-2050.txt already +# uses, so this fixture can be read the same simple way -- split on '|', +# not on whitespace, so title/commemoration/displaced text keeps its own +# spaces; only tempora, which nothing in this project parses further than +# pass-through display, is space-collapsed for a cheap column-count check). +import json +import os +import sys + + +def main(): + if len(sys.argv) != 3: + print(f"usage: {sys.argv[0]} <snapshot-dir> <out-file>", file=sys.stderr) + return 2 + snapshot_dir, out_path = sys.argv[1], sys.argv[2] + src = os.path.join(snapshot_dir, "missalemeum", "en") + rows = [] + for fname in sorted(os.listdir(src)): + if not fname.endswith(".json"): + continue + date = fname[:-5] + with open(os.path.join(src, fname), encoding="utf-8") as f: + data = json.load(f) + first = data[0]["info"] + for other in data[1:]: + o = other["info"] + for k in ("rank", "colors", "tempora", "commemorations", "displaced"): + if first[k] != o[k]: + print(f"WARNING: {date} masses disagree on {k}: {first[k]!r} vs {o[k]!r}", file=sys.stderr) + comm_titles = [c["title"] for c in first["commemorations"]] + disp_titles = [d["title"] for d in first["displaced"]] + for t in [first["title"]] + comm_titles + disp_titles: + if "|" in t or ";" in t: + print(f"ERROR: {date}: field {t!r} contains a delimiter this fixture uses", file=sys.stderr) + return 1 + colors = "".join(sorted(first["colors"])) + tempora = (first["tempora"] or "-").replace(" ", "_") + comms = ";".join(comm_titles) or "-" + disp = ";".join(disp_titles) or "-" + rows.append(f"{date}|{first['rank']}|{colors}|{first['title']}|{tempora}|{comms}|{disp}|{len(data)}") + + if len(rows) != 730: + print(f"ERROR: expected 730 days, got {len(rows)}", file=sys.stderr) + return 1 + + with open(out_path, "w", encoding="utf-8") as f: + f.write("\n".join(rows) + "\n") + print(f"wrote {len(rows)} lines to {out_path}", file=sys.stderr) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) |
