test(extract): hand-built office fixtures with frozen extracted text
Three hand-laid OOXML containers, every part written out by hand and zipped
with a fixed date_time so they are byte-reproducible. No converter output
anywhere in them: a .docx written by the converter and read by the converter
proves only that the converter agrees with itself, and would stay green through
any conversion defect that is symmetric -- which is most of them.
two-line-krav.docx heading + label/value on one line (the docx mirror of
the PDF fixture)
no-styles-krav.docx the SAME document without word/styles.xml
two-line-krav.xlsx sheet name as heading + label/value on one row
THE FIXTURES FOUND A REAL DEFECT IN THE SEAM THEY WERE MEANT TO PIN. The
converter call used pypandoc's TEXT entry point, which takes an `encoding`
because it treats its source as text -- and that corrupts a zip. The xlsx
fixture failed with `Failed to unpack XLSX archive: not enough bytes` while
reading correctly from disk with the same binary. The docx of the same shape
happened to survive, which is the part worth writing down: the defect is silent
for some inputs and fatal for others, so "it worked on the file I tried" was
never evidence. Input now goes through a temporary file.
Two measurements while building, both the same shape -- structurally valid
input, silently reduced output, exit code 0, no warning:
- Without word/styles.xml the docx extracts as flat prose with no heading. A
fixture lacking that part would pin the body and pin nothing about structure.
Committed as a negative control that RUNS rather than a sentence in a README.
- With inline strings rather than a shared string table, the xlsx extracts with
the sheet name intact and every cell value gone. The fixture uses a dimension
element and a shared string table instead.
The frozen literals are pinned to a NAMED converter version, asserted beside
them: a frozen literal without one says "these bytes" without saying what
produced them.
Suite 908 -> 913. Fixtures regenerate byte-identically.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
cd7b792aaf
commit
66a44f173b
7 changed files with 274 additions and 6 deletions
|
|
@ -26,6 +26,7 @@ from __future__ import annotations
|
|||
import csv
|
||||
import functools
|
||||
import io
|
||||
import tempfile
|
||||
import warnings
|
||||
from collections.abc import Callable, Sequence
|
||||
from html.parser import HTMLParser
|
||||
|
|
@ -250,13 +251,30 @@ def _convert_bytes(source: bytes, to: str, format: str, extra_args: Sequence[str
|
|||
would otherwise need the binary present and a real office document, which
|
||||
would make the seam's own logic untestable on a machine without the extra.
|
||||
The conversion itself is covered by the frozen-text fixtures instead.
|
||||
|
||||
THE INPUT GOES THROUGH A FILE, NOT THROUGH THE TEXT ENTRY POINT. Every
|
||||
format here is a binary container, and the converter's text entry point
|
||||
takes an `encoding` because it treats its source as text -- which corrupts
|
||||
a zip. Measured: a hand-laid `.xlsx` that pandoc reads correctly from disk
|
||||
fails through the text path with `Failed to unpack XLSX archive: not enough
|
||||
bytes`. A `.docx` of the same shape happened to survive, which is what
|
||||
makes this worth writing down: the defect is SILENT for some inputs and
|
||||
fatal for others, so "it worked on the file I tried" is not evidence here.
|
||||
|
||||
The temporary directory is removed on every path, including the failure
|
||||
one, and nothing outside it is written.
|
||||
"""
|
||||
import pypandoc
|
||||
|
||||
from ._pandoc import converter_path
|
||||
|
||||
with converter_path():
|
||||
return str(pypandoc.convert_text(source, to, format=format, extra_args=list(extra_args)))
|
||||
with tempfile.TemporaryDirectory() as staging:
|
||||
staged = Path(staging) / f"input.{format}"
|
||||
staged.write_bytes(source)
|
||||
with converter_path():
|
||||
return str(
|
||||
pypandoc.convert_file(str(staged), to, format=format, extra_args=list(extra_args))
|
||||
)
|
||||
|
||||
|
||||
def _extract_office(suffix: str, data: bytes) -> str:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue