Add the Python variant, agreeing with Go byte for byte

A second, independent implementation of the same contract, in the same repo:

- swehockey/dom.py builds the tree on html.parser, so the variant has no
  runtime dependencies; the only HTML5 behaviour it depends on - stray <tr>
  landing in an implicit <tbody> - is handled explicitly by table_rows().
- parse.py mirrors the Go layout profiles, dual-render checks, carry-forward and
  invariants; a DriftError is raised in the same places with the same advice.
- cli.py offers the same three commands, flags and exit codes as the Go main.
- tests/ assert against the Go golden files, so the suite is also a
  cross-implementation check. 23 offline tests plus an opt-in live test.

Verified against the live site: JSON and CSV are byte-identical to the Go
output (364 games, 102536 bytes / 365 lines), and the full archive crawl gives
the same 27 seasons, 2119 games and 1779 played.

Also split the DriftError hint out in Go, so a golden mismatch no longer tells
the reader to extend layouts[].
This commit is contained in:
Mats Tornberg committed 2026-09-27 08:53:23 +00:00
1 parent 6b701819ca
commit 47e1811d9e
15 files changed
+1821 -3

No files matched your search

+4 -1
View File
@@ -104,7 +104,10 @@ func emit(out, check string, b []byte) error {
case err != nil:
return fmt.Errorf("golden file %s: %w", check, err)
default:
return &DriftError{Msg: fmt.Sprintf("output no longer matches %s: %s", check, firstDiff(golden, b))}
// A golden mismatch is not a layout problem, so it gets its own
// advice instead of the "extend layouts[]" one.
return &DriftError{Msg: fmt.Sprintf("output no longer matches %s: %s", check, firstDiff(golden, b)),
Hint: " - regenerate the golden file only after reviewing the change"}
}
}
if out == "" {