[object Object]

← back to Paul Conrad Archive

Fix PEP701 nested-quote f-strings (broke Kamatera py3.10); add py3.10 py_compile test over all sources (proven red on the bug)

f12cde5f207781227a2a08cb8c0495b3d4340093 · 2026-09-24 18:11:45 -0700 · Steve Abrams

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit f12cde5f207781227a2a08cb8c0495b3d4340093
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Sep 24 18:11:45 2026 -0700

    Fix PEP701 nested-quote f-strings (broke Kamatera py3.10); add py3.10 py_compile test over all sources (proven red on the bug)
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---
 src/conrad/crawlers/secondary_citations.py |  6 +++---
 tests/test_py310_syntax.py                 | 21 +++++++++++++++++++++
 2 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/src/conrad/crawlers/secondary_citations.py b/src/conrad/crawlers/secondary_citations.py
index 51facc8..c6e156d 100644
--- a/src/conrad/crawlers/secondary_citations.py
+++ b/src/conrad/crawlers/secondary_citations.py
@@ -353,8 +353,8 @@ class SecondaryCitations(Crawler):
                 verified.append((url, quote, date_quote))
             else:
                 why = "page unavailable" if t is None else "quote not found on page"
-                self.rejected.append(f"{c["slug"]} @ {url} ({why})")
-                self.error(url, f"citation rejected for {c["slug"]}: {why}")
+                self.rejected.append(f"{c['slug']} @ {url} ({why})")
+                self.error(url, f"citation rejected for {c['slug']}: {why}")
         if not verified:
             return
         d = _dates(c)
@@ -367,7 +367,7 @@ class SecondaryCitations(Crawler):
             if c.get("note") and i == 0:
                 note += f" | caveat: {c['note']}"
             rec = CartoonRecord(
-                canonical_id=f"sec:{c["slug"]}", identifier=f"{c["slug"]}@{url}", granularity="item",
+                canonical_id=f"sec:{c['slug']}", identifier=f"{c['slug']}@{url}", granularity="item",
                 title=c["title"], caption=c.get("caption"), description=c.get("desc"),
                 publication=c.get("pub"), rights_text=rights.COPYRIGHT_NOTE, notes=note if i == 0 else None,
                 repository="Secondary citation", collection_name=SITE.get(url, "secondary web page"),
diff --git a/tests/test_py310_syntax.py b/tests/test_py310_syntax.py
new file mode 100644
index 0000000..3e8edfb
--- /dev/null
+++ b/tests/test_py310_syntax.py
@@ -0,0 +1,21 @@
+"""Kamatera runs Python 3.10: every source file must parse under 3.10 grammar (e.g. no PEP 701 nested-quote f-strings)."""
+import ast
+import pathlib
+import sys
+
+import pytest
+
+ROOT = pathlib.Path(__file__).resolve().parents[1]
+FILES = sorted(p for d in ("src", "scripts", "tests") for p in (ROOT / d).rglob("*.py"))
+
+
+@pytest.mark.skipif(sys.version_info < (3, 12), reason="running ON 3.10/3.11 already proves it")
+@pytest.mark.parametrize("path", FILES, ids=lambda p: str(p.relative_to(ROOT)))
+def test_parses_as_py310(path):
+    import subprocess
+    # ast feature_version does not enforce PEP 701 f-string rules, so check with a real 3.10 if present
+    py310 = next((p for p in ("/opt/homebrew/bin/python3.10", "/usr/local/bin/python3.10", str(pathlib.Path.home() / ".local/share/uv/python/cpython-3.10-macos-aarch64-none/bin/python3.10")) if pathlib.Path(p).exists()), None)
+    if py310 is None:
+        pytest.skip("no python3.10 interpreter on this host")
+    r = subprocess.run([py310, "-m", "py_compile", str(path)], capture_output=True, text=True)
+    assert r.returncode == 0, r.stderr

← e4fc551 Copyright rail layer 2: refuse image/PDF responses by Conten  ·  back to Paul Conrad Archive  ·  NCR citation: use live natcath.org original (200, no robots) e1a4fb4 →