Skip to content

Input Contracts

Most users should pass supported data directly to Extractor. Integrations can prepare input explicitly when they need to inspect normalized data or reuse one document conversion across schema and extraction operations.

PreparedInput

Normalized extraction input and its owned resources.

InputProcessor creates this contract before planning or row processing. Application code normally receives an ExtractionResult instead; this type is primarily useful when calling FileReader directly.

Attributes:

Name Type Description
dataframe DataFrame

Source rows retained for planning, provenance, and optional DataFrame output.

pdf_rows Dict[int, PdfRow]

Positional row mappings for multimodal PDF payloads.

planning_sample Optional[str]

Text extracted once from a converted document for schema planning. Existing PDFs usually leave this unset and are attached directly to the planning request.

owned_paths List[Path]

Temporary files that must be deleted after processing. InputProcessor.prepared handles this automatically.

Source code in structx/core/input.py
@dataclass
class PreparedInput:
    """Normalized extraction input and its owned resources.

    ``InputProcessor`` creates this contract before planning or row processing.
    Application code normally receives an ``ExtractionResult`` instead; this
    type is primarily useful when calling ``FileReader`` directly.

    Attributes:
        dataframe: Source rows retained for planning, provenance, and optional
            DataFrame output.
        pdf_rows: Positional row mappings for multimodal PDF payloads.
        planning_sample: Text extracted once from a converted document for
            schema planning. Existing PDFs usually leave this unset and are
            attached directly to the planning request.
        owned_paths: Temporary files that must be deleted after processing.
            ``InputProcessor.prepared`` handles this automatically.
    """

    dataframe: pd.DataFrame
    pdf_rows: Dict[int, PdfRow] = field(default_factory=dict)
    planning_sample: Optional[str] = None
    owned_paths: List[Path] = field(default_factory=list)
    _closed: bool = field(default=False, init=False, repr=False)

    @property
    def closed(self) -> bool:
        """Whether temporary resources owned by this input were released."""
        return self._closed

    def ensure_open(self) -> None:
        """Reject reuse after explicit cleanup."""
        if self._closed:
            raise RuntimeError("Prepared input is closed")

    def close(self) -> None:
        """Release owned temporary resources. This operation is idempotent."""
        if self._closed:
            return
        for path in self.owned_paths:
            Path(path).unlink(missing_ok=True)
        self.owned_paths.clear()
        self._closed = True

    def row_payload(
        self, position: int, row: pd.Series, target_columns: List[str]
    ) -> RowPayload:
        """Build the text or PDF payload for one positional input row."""
        self.ensure_open()
        pdf_row = self.pdf_rows.get(position)
        if pdf_row is not None:
            return pdf_row
        return row[target_columns].to_markdown()

closed property

Whether temporary resources owned by this input were released.

close()

Release owned temporary resources. This operation is idempotent.

Source code in structx/core/input.py
def close(self) -> None:
    """Release owned temporary resources. This operation is idempotent."""
    if self._closed:
        return
    for path in self.owned_paths:
        Path(path).unlink(missing_ok=True)
    self.owned_paths.clear()
    self._closed = True

ensure_open()

Reject reuse after explicit cleanup.

Source code in structx/core/input.py
def ensure_open(self) -> None:
    """Reject reuse after explicit cleanup."""
    if self._closed:
        raise RuntimeError("Prepared input is closed")

row_payload(position, row, target_columns)

Build the text or PDF payload for one positional input row.

Source code in structx/core/input.py
def row_payload(
    self, position: int, row: pd.Series, target_columns: List[str]
) -> RowPayload:
    """Build the text or PDF payload for one positional input row."""
    self.ensure_open()
    pdf_row = self.pdf_rows.get(position)
    if pdf_row is not None:
        return pdf_row
    return row[target_columns].to_markdown()

PdfRow

A PDF payload associated with one source row.

Attributes:

Name Type Description
pdf_path Path

PDF sent to Instructor's multimodal input.

source Path

Original user-supplied document path. For converted documents, this differs from pdf_path.

Source code in structx/core/input.py
@dataclass(frozen=True)
class PdfRow:
    """A PDF payload associated with one source row.

    Attributes:
        pdf_path: PDF sent to Instructor's multimodal input.
        source: Original user-supplied document path. For converted documents,
            this differs from ``pdf_path``.
    """

    pdf_path: Path
    source: Path

Resource Ownership

FileReader.read_file() returns a PreparedInput. Existing PDFs are borrowed and never deleted. Converted documents place generated PDFs in owned_paths.

One-shot Extractor methods clean those paths automatically. The public preparation context managers keep prepared input open across schema and extraction methods, then guarantee cleanup when the context exits:

from structx import Extractor

with extractor.prepare_input(data="agreement.docx") as prepared:
    print(prepared.dataframe)
    print(prepared.pdf_rows[0].pdf_path)
    schema = extractor.get_schema(
        data=prepared,
        query="extract agreement terms",
    )
    result = extractor.extract(
        data=prepared,
        query="extract agreement terms",
        model=schema,
    )

Use async with extractor.prepare_input_async(...) when preparation may perform blocking file parsing or document conversion. The prepared object can be inspected for metering or status updates before any model-backed operation. Lower-level callers can still use the idempotent PreparedInput.close() method directly when a context manager is not suitable.

See Supported Formats for accepted public input types and document conversion behavior.