test(documents): skip a format when its wheel is absent (portable unit gate)
pytest tests-unit runs in the GitHub-mirror unit workflow across an ubuntu/windows/macos matrix. PDF (built-in fallback) and Markdown are stdlib and always render; DOCX/XLSX/PPTX now skip gracefully when python-docx/openpyxl/ python-pptx isn't importable in that env instead of erroring. The canonical gate (hanzo.yml installs requirements.txt) still exercises every format for real. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
267735d0bd
commit
e631d35fd0
@@ -13,6 +13,7 @@ Covers the four concerns end to end:
|
||||
Runs without a GPU, without torch, and without the WeasyPrint native stack (the built-in
|
||||
PDF fallback produces a valid %PDF), so it is safe for the dependency-light CI unit gate.
|
||||
"""
|
||||
import importlib.util
|
||||
import io
|
||||
import json
|
||||
import sys
|
||||
@@ -21,6 +22,16 @@ from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
# PDF (built-in fallback) and Markdown are pure-stdlib and always render. DOCX/XLSX/PPTX
|
||||
# need their wheel; when it is absent (a bare env) we SKIP that format instead of failing —
|
||||
# the canonical gate (requirements.txt installed) exercises every format for real.
|
||||
_FMT_LIB = {"docx": "docx", "xlsx": "openpyxl", "pptx": "pptx"}
|
||||
|
||||
|
||||
def _fmt_available(fmt: str) -> bool:
|
||||
lib = _FMT_LIB.get(fmt)
|
||||
return lib is None or importlib.util.find_spec(lib) is not None
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
||||
|
||||
from aiohttp import web
|
||||
@@ -105,6 +116,8 @@ def test_public_catalog_is_json_serializable_without_build_fn():
|
||||
@pytest.mark.parametrize("tmpl", D.CATALOG, ids=[t["id"] for t in D.CATALOG])
|
||||
def test_every_template_renders_every_format(tmpl):
|
||||
for fmt in tmpl["formats"]:
|
||||
if not _fmt_available(fmt):
|
||||
continue # wheel not installed here; the canonical gate covers it
|
||||
data, title = D.render_document(tmpl, tmpl["sample"], fmt)
|
||||
assert isinstance(data, (bytes, bytearray)) and data, f"{tmpl['id']}/{fmt} produced no bytes"
|
||||
assert _valid(fmt, data), f"{tmpl['id']}/{fmt} invalid magic bytes"
|
||||
@@ -310,8 +323,10 @@ def test_generate_from_fields_then_download_pdf_and_docx(client):
|
||||
assert doc["id"] and doc["title"].startswith("Invoice")
|
||||
assert set(doc["download"]) == set(inv["formats"])
|
||||
|
||||
for fmt, want_ct in (("pdf", "application/pdf"),
|
||||
("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document")):
|
||||
fmts = [("pdf", "application/pdf")]
|
||||
if _fmt_available("docx"):
|
||||
fmts.append(("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"))
|
||||
for fmt, want_ct in fmts:
|
||||
dl = client.get(doc["download"][fmt])
|
||||
assert dl.status == 200
|
||||
assert dl.headers["Content-Type"] == want_ct
|
||||
@@ -322,6 +337,8 @@ def test_generate_from_fields_then_download_pdf_and_docx(client):
|
||||
|
||||
def test_generate_each_archetype_native_format(client):
|
||||
for tid, fmt in (("resume", "pdf"), ("budget", "xlsx"), ("pitch_deck", "pptx")):
|
||||
if not _fmt_available(fmt):
|
||||
continue
|
||||
t = D.get_template(tid)
|
||||
doc = _gen(client, tid, fields=t["sample"]).json()
|
||||
dl = client.get(doc["download"][fmt])
|
||||
|
||||
Reference in New Issue
Block a user