cadrumo.core.document_shape module

Closed taxonomy of evidence-document shapes derived from content bytes.

Replaces the two-member MediaKind (PDF / IMAGE) that was derived from a declared MIME type. That derivation could not see inside a document, so a ZUGFeRD / Factur-X invoice – a PDF that carries a complete machine- readable EN16931 XML payload as an embedded file – was indistinguishable from a scan of a paper receipt. Both answered PDF, and the most exactly readable document in the corpus was read as rendered prose.

The shape is therefore derived from the bytes themselves. It exists so a reader can ask what can be recovered exactly from this document before choosing a strategy, and so the routing order is inspectable: a document carrying a structured record reaches no model at all.

class DocumentShape(*values)[source]

Bases: StrEnum

What a resolved evidence document actually is, by content.

Members are ordered from most to least exactly readable. The three XML_* members and PDF_EMBEDDED_XML all carry a structured record; everything below them requires text extraction or a model.

XML_CII

Standalone EN16931 Cross Industry Invoice (UN/CEFACT syntax).

XML_UBL

Standalone EN16931 UBL invoice (OASIS syntax).

XML_FACTURAE

Standalone Facturae 3.2.x invoice (the Spanish national format).

PDF_EMBEDDED_XML

PDF carrying a structured invoice as an embedded file (ZUGFeRD / Factur-X).

XML_AEAT_SII

a BATCH of ledger records, not one invoice document.

Deliberately not a member of STRUCTURED_DOCUMENT_SHAPES. That set routes a document into the single-invoice reader, and one SII file declares its record collections at maxOccurs=10000; routing a batch into a singular reader would silently keep the first record and discard the rest. Which family each record belongs to – facturas emitidas, recibidas, a baja, or one of the twelve non-invoice families – is classified per RECORD, never per file.

Type:

AEAT SII submission

XML_AEAT_VERIFACTU

a batch of registro de facturacion records.

Not a member of STRUCTURED_DOCUMENT_SHAPES, for the same reason as XML_AEAT_SII. Its RegistroFactura is a CHOICE of RegistroAlta or RegistroAnulacion repeated to maxOccurs=1000, so a single submission may MIX registrations and cancellations and cannot be classified from the file alone.

Type:

VERI*FACTU submission

PDF_TEXT_LAYER

PDF with an extractable text layer but no structured record.

PDF_SCAN

PDF whose pages carry no extractable text; readable only by rasterising.

IMAGE

A bare image of a document.

UNKNOWN

Bytes matching no recognised shape. Never guessed at, always refused.

STRUCTURED_DOCUMENT_SHAPES: frozenset[DocumentShape]

Shapes carrying a structured SINGLE-INVOICE record, readable with no model.

Membership means “one document, one invoice, readable by parse_einvoice_document”. The AEAT record-batch shapes are excluded on purpose: they are equally structured and equally model-free, but they carry a COLLECTION of ledger records, so admitting them here would route a batch into a reader that returns one invoice and silently drop every record after the first. No single-invoice reader accepts them: the evidence path leaves them outside this set and refuses them as filing artefacts until a dedicated reconciliation reader exists. A future reader would need a collection return type rather than silently discarding records.

Hand-listed rather than derived, so adding a structured member forces a deliberate decision about which of the two readers it belongs to.

PDF_CONTAINER_SHAPES: frozenset[DocumentShape]

Shapes whose bytes are a PDF, whatever the PDF turns out to carry.

The read paths that rasterise pages, or try a text layer before falling back to vision, need exactly this question: is this a PDF container? They previously asked it of MediaKind, which is derived from the STORED MIME TYPE – a label the producer attached, which cannot see inside the document. That is the same blindness the shape probe exists to remove, so asking the label was the one remaining way a caller could be told “PDF” by something that never opened it.

Hand-listed for the same reason as the sets above: a new PDF-carrying shape should force a decision about whether page rasterisation is meaningful for it, rather than being swept in by a name prefix.