mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-11-02 13:12:50 +00:00
fix(verify-layout): escape the docstring's LaTeX macro so the tool stops emitting SyntaxWarning (#480)
`tools/verify_layout.py`'s module docstring explains which documents trigger
the Poppler `-bbox` crash, and names the macro whose absence causes it:
`\hypersetup{pdftitle=...}`. In a non-raw docstring `\h` is an invalid escape
sequence, so compiling the module prints
SyntaxWarning: "\h" is an invalid escape sequence.
Such sequences will not work in the future. Did you mean "\\h"?
on Python 3.12+ (CPython gh-98401 promoted the long-standing
DeprecationWarning to a SyntaxWarning). The 3.15 language reference still
documents the sequence as a SyntaxWarning, with a SyntaxError only "in a
future Python version".
This is on the real path, not a constructed one: /apply Step 5b runs
`python3 tools/verify_layout.py <pdf>` once per document, so the first
invocation after any source change prints the warning into the middle of the
layout report a user is reading to judge their CV. It is also visible in this
repo's own CI log, where `python -m unittest discover -s tests -t . -v` prints
it above the test results.
Reproduce on master:
python3 -W error::SyntaxWarning -c "compile(open('tools/verify_layout.py',
encoding='utf-8').read(), 'tools/verify_layout.py', 'exec')"
raises on master; after this change it is silent.
Escaping (rather than making the docstring raw) keeps the surrounding prose
unchanged, and the single-backtick markup matches the other inline literals in
the same docstring. The rendered text still reads `\hypersetup{...}`.
The new `ToolsCompileWithoutWarnings` case is a pure `compile()` of the source
text of every `tools/*.py` inside `warnings.catch_warnings(record=True)` and
asserts no `SyntaxWarning` or `DeprecationWarning` (3.10 and 3.11 report the
same escape as a DeprecationWarning) - no cache file, no temp file, so it runs
the same on Windows (py_compile's atomic rename over an open
NamedTemporaryFile is what the first version tripped on). It fails on master
and passes here on every Python in the CI matrix, and it guards the next
docstring that quotes a macro.
Verification on Python 3.10, 3.11, 3.12, 3.13 and 3.14: `python3 -m unittest discover -s
tests -t .` (488 tests OK; master is 487), `python3 -W error::SyntaxWarning`
compile of every `tools/*.py`, `tests/test_changelog_structure.py`.
This commit is contained in:
3 files changed
+49
-1
No files matched your search
@@ -132,6 +132,17 @@ per-file diff commands.
|
||||
The standard `date`-first header already worked; regression coverage checks
|
||||
all three column orders with and without a BOM.
|
||||
|
||||
- **`verify_layout.py` no longer emits a `SyntaxWarning` on every run** (`tools/verify_layout.py`,
|
||||
`tests/test_verify_layout.py`) - the module docstring names the macro whose absence triggers the
|
||||
Poppler `-bbox` crash, `\hypersetup{pdftitle=...}`, and a bare `\h` in a non-raw docstring is an
|
||||
invalid escape sequence. Python 3.12+ prints `SyntaxWarning: "\h" is an invalid escape sequence`
|
||||
the first time the module is compiled (CPython gh-98401) - it shows up in this repo's own CI log,
|
||||
and in the middle of `/apply` Step 5b's layout report. The 3.15 language reference still
|
||||
documents the sequence as a `SyntaxWarning`, with a `SyntaxError` only in a future Python
|
||||
version. Escaped in the docstring; the new `ToolsCompileWithoutWarnings` case compiles the
|
||||
source of every `tools/*.py` with warnings captured and fails on the unescaped version, so the
|
||||
next docstring that quotes a LaTeX macro is caught too.
|
||||
|
||||
- **`/apply` Step 5b now actually runs the page-count check it claimed Step 5d ran**
|
||||
(`.claude/commands/apply.md`, `tests/test_apply_page_count.py`) - the 5b prose said
|
||||
"Page count is not checked here - that is `verify_pdf.py --pages`'s job, and Step 5d already
|
||||
|
||||
@@ -16,6 +16,7 @@ from contextlib import redirect_stdout
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
from tools import verify_layout
|
||||
from tools.verify_layout import Line, Page, find_orphans, main, parse_pdf, report
|
||||
|
||||
A4_HEIGHT = 842.0
|
||||
@@ -164,5 +165,41 @@ class TestExtractorFailure(unittest.TestCase):
|
||||
self.assertIn("skipped:", err.getvalue())
|
||||
|
||||
|
||||
class ToolsCompileWithoutWarnings(unittest.TestCase):
|
||||
"""Every tool's source must compile clean.
|
||||
|
||||
`verify_layout.py`'s docstring documents LaTeX macros, and a bare `\\h` in a
|
||||
non-raw docstring is an invalid escape sequence: Python 3.12+ emits a
|
||||
SyntaxWarning when the module is compiled (CPython gh-98401), 3.10 and 3.11
|
||||
a DeprecationWarning, so the test records both; the language
|
||||
reference still documents it as a warning in 3.15, with a SyntaxError only
|
||||
in a future Python version. The tool is run per-document from `/apply`, so
|
||||
the warning lands in the middle of a verification report. Compiling is a
|
||||
pure `compile()` over the source text - no cache file, no temp file - so the
|
||||
check costs nothing and covers every `tools/*.py`, guarding the next
|
||||
docstring that quotes a macro too.
|
||||
"""
|
||||
|
||||
def test_sources_have_no_invalid_escape_sequences(self):
|
||||
import warnings
|
||||
|
||||
tools_dir = Path(verify_layout.__file__).resolve().parent
|
||||
sources = sorted(tools_dir.glob("*.py"))
|
||||
self.assertIn(Path(verify_layout.__file__).resolve(), sources)
|
||||
offenders: dict[str, list[str]] = {}
|
||||
for source in sources:
|
||||
with warnings.catch_warnings(record=True) as caught:
|
||||
warnings.simplefilter("always")
|
||||
compile(source.read_text(encoding="utf-8"), str(source), "exec")
|
||||
syntax = [
|
||||
str(w.message)
|
||||
for w in caught
|
||||
if issubclass(w.category, (SyntaxWarning, DeprecationWarning))
|
||||
]
|
||||
if syntax:
|
||||
offenders[source.name] = syntax
|
||||
self.assertEqual({}, offenders, "tools/*.py warn about invalid escapes when compiled")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -32,7 +32,7 @@ than inventing a layout failure. A broken extractor has two distinct causes: an
|
||||
all, and Poppler 26.0x before 26.05 aborts `-bbox`/`-bbox-layout`/`-htmlmeta` on a PDF
|
||||
whose Info dictionary carries an empty string in any field - which `hyperref` writes for
|
||||
every field it does not set, so any `lualatex`/`pdflatex` document built with `hyperref`
|
||||
and no `\hypersetup{pdftitle=...}` triggers a real Poppler crashing on a legal PDF (#451).
|
||||
and no `\\hypersetup{pdftitle=...}` triggers a real Poppler crashing on a legal PDF (#451).
|
||||
Line height serves
|
||||
as a font-size proxy to spot section headings; left edge (xMin) separates bullet lines
|
||||
from entry headers.
|
||||
|
||||
Reference in new issue
Block a user