Emit a structured failure line and increment FAIL. Phase 5 r3 format: ` [: ]: ` — no "FAIL:" label, so output is grep-parseable as `^[^:]+:[0-9]*:? .+$`. The prefix `FAIL:` is deliberately removed; the global FAIL counter (summarised in main()) is the authoritative
(msg, reason=None, *, line=None)
| 454 | |
| 455 | |
| 456 | def fail(msg, reason=None, *, line=None): |
| 457 | """Emit a structured failure line and increment FAIL. |
| 458 | |
| 459 | Phase 5 r3 format: `<path>[:<line>]: <reason>` — no "FAIL:" label, so |
| 460 | output is grep-parseable as `^[^:]+:[0-9]*:? .+$`. The prefix `FAIL:` is |
| 461 | deliberately removed; the global FAIL counter (summarised in main()) is |
| 462 | the authoritative count of failures per run. |
| 463 | |
| 464 | Preferred forms: |
| 465 | fail("quality/INDEX.md", "file missing") |
| 466 | -> " quality/INDEX.md: file missing" |
| 467 | fail("quality/INDEX.md", "missing required field 'x'", line=42) |
| 468 | -> " quality/INDEX.md:42: missing required field 'x'" |
| 469 | |
| 470 | Legacy single-arg form (transitional; still supported — most v1.4.x |
| 471 | messages already embed a path-like token): |
| 472 | fail("BUGS.md missing or not a file") |
| 473 | -> " BUGS.md missing or not a file" |
| 474 | """ |
| 475 | global FAIL |
| 476 | if reason is None: |
| 477 | print(f" {msg}") |
| 478 | elif line is None: |
| 479 | print(f" {msg}: {reason}") |
| 480 | else: |
| 481 | print(f" {msg}:{line}: {reason}") |
| 482 | FAIL += 1 |
| 483 | |
| 484 | |
| 485 | def pass_(msg): |
no outgoing calls
no test coverage detected