(path: Path, label: str, validator: RowValidator)
| 299 | |
| 300 | |
| 301 | def load_jsonl(path: Path, label: str, validator: RowValidator) -> list[JsonRow]: |
| 302 | if not path.exists(): |
| 303 | raise SystemExit(f"{label} missing: {path}") |
| 304 | |
| 305 | rows: list[JsonRow] = [] |
| 306 | with path.open(encoding="utf-8") as handle: |
| 307 | for line_number, raw_line in enumerate(handle, start=1): |
| 308 | if not raw_line.strip(): |
| 309 | raise SystemExit(f"{path}:{line_number}: blank JSONL rows are not allowed") |
| 310 | try: |
| 311 | parsed: object = json.loads(raw_line) |
| 312 | except json.JSONDecodeError as exc: |
| 313 | raise SystemExit(f"{path}:{line_number}: invalid JSON: {exc.msg}") from exc |
| 314 | if not isinstance(parsed, dict): |
| 315 | raise SystemExit(f"{path}:{line_number}: expected a JSON object") |
| 316 | row = {str(key): value for key, value in parsed.items()} |
| 317 | validator(row, path, line_number) |
| 318 | rows.append(row) |
| 319 | return rows |
| 320 | |
| 321 | |
| 322 | def require_exact_fields(row: JsonRow, expected: set[str], path: Path, line_number: int) -> None: |
no outgoing calls
no test coverage detected