Skip to content

Python API

import complydoc as cd

Everything on this page is public. A breaking change to it changes the minor version. Anything in the package that is not on this page is internal.

Audits and inspection

complydoc.aiter_audit async

aiter_audit(
    target: str | PathLike[str],
    *,
    components: Sequence[str] = COMPONENTS,
    **options: Unpack[AuditOptions],
) -> AsyncIterator[DocumentReport | SkipRecord]

iter_audit for asynchronous code, reading each document in a worker thread.

complydoc.check_facts

check_facts(
    report: AuditReport,
    facts: Iterable[Fact | str],
    *,
    threshold: float = FUZZY_THRESHOLD,
) -> list[FactCheck]

Whether each fact appears in the report's extracted text.

The report must have been produced with extracted_text=True. Results are keyed by the loader's name for loader output, and by report otherwise.

complydoc.compare_chunkers

compare_chunkers(
    chunkers: Mapping[str, Any],
    documents: Any,
    **options: Any,
) -> ChunkComparison

inspect_chunks for each named splitter on the same documents.

complydoc.compare_loaders

compare_loaders(
    loaders: Mapping[str, Any] | Sequence[Any],
    *,
    config: Config | None = None,
    components: Sequence[str] = COMPONENTS,
    reveal: bool = False,
    extracted_text: bool = True,
    models: Sequence[str] | None = None,
    allow_network: bool = False,
    paths: str
    | PathLike[str]
    | Sequence[str | PathLike[str]]
    | None = None,
    facts: Iterable[Fact | str] | None = None,
    fact_threshold: float = FUZZY_THRESHOLD,
    cache_dir: str | PathLike[str] | None = None,
    verify_with: str | VisionModel | None = None,
    verify_scope: str = "flagged",
) -> AuditReport

Run several loaders on the same input and report where their output differs.

loaders maps a name to a loader, or is a sequence of loaders, each named after its class. Anything inspect_documents accepts as a source is accepted as a loader, including documents already loaded. The first is the baseline the report's findings are built from.

The comparison is in report.loader_comparison. Each document's extractions lists every loader's reading of it, first the baseline's, and with extracted_text on, each page carries the other loaders' text in readings.

allow_network applies to every loader. Each one's connections are recorded in its row of report.loader_comparison.loaders.

With paths, a folder, a file or a list of files, each loader is a callable taking a file path, such as a loader class or a complydoc.loaders.parsers preset, and runs once per file. Files a loader raises on are recorded in its row.

cache_dir stores each loader's output per file when paths is given, so a later run does not parse unchanged files again; see complydoc.loaders.cache.

facts are passages the documents are expected to contain. Each is checked against every loader's text; see complydoc.extraction.facts.

verify_with reads the baseline's pages again with a vision model of the caller's, as full_audit does, rendered from the files the loaders read. The vision reading joins each page's readings, so it can be put beside any loader's, with what each one cost.

complydoc.cost_audit

cost_audit(
    target: str | PathLike[str],
    **options: Unpack[AuditOptions],
) -> AuditReport

Estimate what these documents would cost an LLM to read.

Per model and per architecture — the text layer, the text layer with OCR behind it, and every page sent as an image.

complydoc.extract_text

extract_text(
    target: str | Path,
    *,
    config: Config | None = None,
    mask: bool = True,
    reveal: bool = False,
    ocr: bool = True,
    recurse: bool = True,
    password: str = "",
    extractor: str | None = None,
    model: str | None = None,
    max_tokens: int | None = None,
) -> TextResult

Read a folder's text, masked, with token counts and what went wrong.

ocr is on by default here, unlike the audit, so scanned pages are read.

mask=False returns the text as the page says it, with no scan run at all. reveal=True runs the scan and reports the counts while leaving the values in place.

complydoc.full_audit

full_audit(
    target: str | PathLike[str],
    **options: Unpack[AuditOptions],
) -> AuditReport

Audit a file or folder on every component.

Cost, readiness and the identifier scan, with the global readiness score and the quick wins that follow from all three.

complydoc.inspect_chunks

inspect_chunks(
    splitter: Any,
    documents: Any = None,
    *,
    name: str | None = None,
    config: Config | None = None,
    model: str | None = None,
    min_tokens: int = 20,
    max_tokens: int | None = None,
    facts: Iterable[Fact | str] | None = None,
    fact_threshold: float = FUZZY_THRESHOLD,
    questions: Iterable[
        Question | Mapping[str, Any] | Sequence[str]
    ]
    | None = None,
    top_k: int = 5,
) -> ChunkReport

Split documents with splitter and inspect the chunks.

With documents omitted, splitter is taken to be the chunks themselves. max_tokens enables the oversized flag. Token counts use model's encoding, or the headline model's.

complydoc.inspect_documents

inspect_documents(
    source: Any,
    *,
    name: str | None = None,
    config: Config | None = None,
    components: Sequence[str] = COMPONENTS,
    reveal: bool = False,
    extracted_text: bool = True,
    models: Sequence[str] | None = None,
    allow_network: bool = False,
) -> AuditReport

Report on the documents a loader produced.

source is a loader, a callable returning documents, a list of documents, or a single document. A loader is run inside the network guard, and any connection it attempts is recorded in report.loader.network_attempts; a loader that fails because a connection was refused produces a report with no documents and the failure in report.loader.error. Any other exception a loader raises is not caught.

allow_network=True lets the loader's connections through, for loaders that call a hosted service. Each lookup and connection is still recorded, the report states that network access was allowed, and everything complydoc does after loading stays behind the guard.

extracted_text is on by default here, unlike full_audit.

complydoc.iter_audit

iter_audit(
    target: str | PathLike[str],
    *,
    components: Sequence[str] = COMPONENTS,
    **options: Unpack[AuditOptions],
) -> Iterator[DocumentReport | SkipRecord]

Yield each document's report entry as it is read, and each skipped file.

Takes the options of full_audit. The network guard is armed while a document is read and released between documents. Raises FileNotFoundError for a missing path when called.

complydoc.readiness_audit

readiness_audit(
    target: str | PathLike[str],
    **options: Unpack[AuditOptions],
) -> AuditReport

Measure how ready these documents are to extract data from.

report.documents[i].readiness.signals holds the signals. A signal that could not be measured is reported as not applicable.

complydoc.security_audit

security_audit(
    target: str | PathLike[str],
    **options: Unpack[AuditOptions],
) -> AuditReport

Find personal and financial identifiers, and nothing else.

Values arrive masked. report.documents[i].sensitive.matches carries each one with its severity and its evidence tier — confirmed where a checksum passed, down to model for a statistical guess.

Strings

complydoc.count_tokens

count_tokens(
    text: str,
    model: str | None = None,
    *,
    config: Config | None = None,
) -> TokenCount

Tokens in text for model, or for the headline model when none is given.

complydoc.find_hidden

find_hidden(
    text: str,
    *,
    config: Config | None = None,
    reveal: bool = False,
) -> list[ContentFinding]

Invisible characters and instruction-like passages in text.

A string has no rendering to check, so visibility is not_measured except for characters that are invisible by definition, such as Unicode tag characters.

complydoc.mask_text

mask_text(
    text: str, *, config: Config | None = None
) -> MaskedText

text with each identifier replaced, strongest evidence first.

complydoc.scan_text

scan_text(
    text: str,
    *,
    config: Config | None = None,
    reveal: bool = False,
) -> TextScan

Personal and financial identifiers in text, masked unless reveal.

Reports and tests

complydoc.diff_reports

diff_reports(
    old: AuditReport,
    new: AuditReport,
    *,
    score_tolerance: float = 0.5,
) -> ReportDiff

Changes from old to new. Score changes smaller than score_tolerance are ignored.

complydoc.expect

expect(report: AuditReport) -> Expectation

Start a chain of checks on report.

complydoc.load_config

load_config(config_dir: Path | None = None) -> Config

Load the three config files from config_dir, defaulting to the shipped set.

complydoc.load_report

load_report(
    source: str | PathLike[str] | Mapping[str, Any],
) -> AuditReport

An AuditReport from a JSON file written by write_json, or from its parsed data.

Raises ValueError for a schema_version not in READABLE_SCHEMA_VERSIONS. Fields missing from an older report take their default values.

complydoc.write_chunks_html

write_chunks_html(
    result: ChunkReport | ChunkComparison,
    path: str | Path,
    *,
    source: str = "",
) -> Path

Write a chunk report or splitter comparison as one self-contained HTML file.

source names what was split, for the page heading. Previews and identifiers are masked, as they are in the report.

complydoc.write_diff_html

write_diff_html(
    diff: ReportDiff,
    path: str | Path,
    *,
    old: str = "",
    new: str = "",
) -> Path

Write the result of diff_reports as one self-contained HTML file.

old and new label the two reports in the heading, such as their file names.

complydoc.write_html

write_html(
    report: AuditReport,
    path: str | PathLike[str],
    *,
    config: Config | None = None,
) -> Path

Write the report as one self-contained HTML file, and return where.

Pass the same config the audit used if it was not the default one: the page echoes parts of it, so a report written against a different configuration would describe settings that did not produce it.

complydoc.write_json

write_json(
    report: AuditReport,
    path: str | PathLike[str],
    *,
    detail: Literal["summary", "full"] = "summary",
) -> Path

Write the report as JSON, and return where. Same shape the CLI writes.

detail="summary" leaves out the price of every document on every model and the page geometry the HTML draws with, keeping the folder's cost per model. detail="full" writes every field; use it for anything that reprocesses reports, since a summary reads back without the parts it left out.

Pipeline steps

complydoc.DropHiddenPassages

Bases: Step

Removes invisible characters and instruction-like sentences from the text.

With drop_document, a document containing either is dropped instead. This works on text: hidden formatting in the source file is detected by an audit, not here. Invisible characters include zero-width joiners, which some scripts use.

complydoc.MaskIdentifiers

Bases: Step

Replaces identifiers in the text, and in string metadata values when metadata.

complydoc.Step

Base class: subclasses implement apply on one document's text and metadata.

apply

apply(
    text: str, metadata: dict[str, Any]
) -> tuple[str, dict[str, Any]] | None

The new text and metadata, or None to drop the document.

complydoc.StepChange dataclass

document instance-attribute

document: str | None

The source named in the document's metadata.

complydoc.StripPathMetadata

Bases: Step

Replaces absolute file paths in metadata values with the file name.

Extending

complydoc.Detector

Bases: Protocol

complydoc.DetectorContext dataclass

Everything a detector is given about the category it is running for.

complydoc.Engine

Bases: Protocol

set_threads

set_threads(count: int | None) -> None

Limit the engine's own threading, before it reads its first page.

complydoc.Extractor

Bases: Protocol

Reads the text layer of one page.

available

available() -> bool

Whether this extractor can run here at all.

complydoc.Finding dataclass

A candidate span within one page's text. Carries no value.

confidence class-attribute instance-attribute

confidence: float | None = 1.0

The detector's own score, or None where the detector has none to give.

context_term class-attribute instance-attribute

context_term: str | None = None

Set when a generic pattern was only reported because of a nearby label.

complydoc.Loader

Bases: Protocol

What every format loader must provide.

complydoc.LoaderSpec dataclass

How to build a loader for one file, and what running it involves.

factory instance-attribute

factory: Callable[[str], Any]

Called with a file path; returns a loader or a list of documents.

network class-attribute instance-attribute

network: bool = False

True when the parser sends documents to a hosted service.

price_key class-attribute instance-attribute

price_key: str | None = None

Entry under parsers in pricing.yaml, for the cost per page.

tags class-attribute instance-attribute

tags: tuple[str, ...] = ()

Framework and library names shown beside the loader in reports.

complydoc.Measurement dataclass

What a signal returns.

detail class-attribute instance-attribute

detail: dict[str, Any] = field(default_factory=dict)

Supporting numbers, shown under the row so the value can be checked.

complydoc.Signal

Bases: Protocol

Implemented by every module under readiness/signals/.

why instance-attribute

why: str

The default plain-English sentence. readiness.yaml can override it.

complydoc.all_engines

all_engines() -> list[Engine]

complydoc.all_extractors

all_extractors() -> list[Extractor]

complydoc.parsers

Presets for document parsers, for use with compare_loaders(..., paths=...).

import complydoc as cd

report = cd.compare_loaders(
    {
        "pypdf": PyPDFLoader,
        "docling": cd.parsers.docling(),
        "llamaparse": cd.parsers.llamaparse(tier="cost_effective"),
    },
    paths="./contracts",
    allow_network=True,
)

Each preset returns a LoaderSpec: a factory that builds a loader for one file, whether the parser sends documents to a hosted service, and the parsers entry in pricing.yaml used to estimate its cost per page. The parser libraries are not dependencies; each preset imports its library when it runs and says what to install when it is missing.

A hosted preset only runs with allow_network=True.

LoaderSpec dataclass

How to build a loader for one file, and what running it involves.

factory instance-attribute
factory: Callable[[str], Any]

Called with a file path; returns a loader or a list of documents.

network class-attribute instance-attribute
network: bool = False

True when the parser sends documents to a hosted service.

price_key class-attribute instance-attribute
price_key: str | None = None

Entry under parsers in pricing.yaml, for the cost per page.

tags class-attribute instance-attribute
tags: tuple[str, ...] = ()

Framework and library names shown beside the loader in reports.

docling

docling(
    export: Literal["markdown", "chunks"] = "markdown",
    **options: Any,
) -> LoaderSpec

Docling through langchain-docling, run locally.

export="markdown" returns one document per file; "chunks" returns Docling's own chunks. options are passed to DoclingLoader.

unstructured

unstructured(
    *,
    api: bool = False,
    api_key: str | None = None,
    strategy: Literal[
        "fast", "hi_res", "ocr_only", "auto"
    ] = "fast",
    **options: Any,
) -> LoaderSpec

Unstructured through langchain-unstructured.

api=True partitions through the hosted Unstructured API. options are passed to UnstructuredLoader.

llamaparse

llamaparse(
    *,
    api_key: str | None = None,
    tier: Literal[
        "fast", "cost_effective", "agentic", "agentic_plus"
    ] = "cost_effective",
    **options: Any,
) -> LoaderSpec

LlamaParse, hosted, through the llama-parse package.

tier selects the price entry; parsing options such as the mode are passed in options to LlamaParse.

azure_document_intelligence

azure_document_intelligence(
    *,
    endpoint: str,
    api_key: str,
    model: str = "prebuilt-layout",
    mode: Literal[
        "markdown", "page", "single"
    ] = "markdown",
    **options: Any,
) -> LoaderSpec

Azure AI Document Intelligence, hosted, through langchain-community.

complydoc.register_detector

register_detector(instance: Detector) -> Detector

Add an identifier detector to this process.

A category uses it when its detector is this detector's id; add the category to sensitive.categories, for example with Config.override.

complydoc.register_engine

register_engine(cls: type) -> type

complydoc.register_extractor

register_extractor(cls: type) -> type

Class decorator. Instantiates the extractor once and registers it by id.

The same arrangement the signals use, so the two read alike.

complydoc.register_instruction_classifier

register_instruction_classifier(
    classifier: Classifier | None,
) -> None

Score passages with a classifier as well as the patterns.

classifier takes a passage and returns how likely it is to be an injected instruction, from 0 to 1. A passage at or above instructions.classifier_threshold in hidden.yaml is reported at the model tier. Pass None to remove it.

complydoc ships and downloads no model. The classifier runs inside the network guard, so it has to load from files already on the machine. It is registered in this process only: audits with jobs above 1 run their documents in worker processes that do not have it.

complydoc.register_loader

register_loader(loader: Loader) -> Loader

complydoc.register_signal

register_signal(instance: Signal) -> Signal

Add a readiness signal to every run in this process.

The signal is measured and shown unrated until readiness.signals.<id> is configured, for example with Config.override.

complydoc.supported_extensions

supported_extensions() -> tuple[str, ...]

Errors

complydoc.ConfigError

Bases: RuntimeError

Raised when a configuration file is missing or fails validation.

complydoc.ExpectationError

Bases: AssertionError

A report did not meet an expectation.

complydoc.LoaderError

Bases: RuntimeError

A file could not be opened or parsed. Always caught; never fatal to a run.

complydoc.NetworkAccessError

Bases: RuntimeError

Raised when any code attempts to open a network connection.

complydoc.UnknownModelError

Bases: ValueError

A model was asked for by name and is not in the pricing config.

Results and types

complydoc.AuditOptions

Bases: TypedDict

Everything the four entry points accept beyond the folder itself.

One set for all of them. An option that does not apply to the components being run is ignored.

config instance-attribute

config: Config | None

A loaded configuration. load_config() is used when this is absent.

ocr instance-attribute

ocr: bool

Read pages with no text layer. Slower, and finds what a scan is hiding.

reveal instance-attribute

reveal: bool

Put identifiers in the report in full. Off, and the report says which it was.

models instance-attribute

models: Sequence[str] | None

Price against these models instead of the configured comparison.

sample instance-attribute

sample: int | None

Audit this many documents, keeping each file type's share of the folder.

jobs instance-attribute

jobs: int

Worker processes. 1 by default; 0 reads the folder and decides.

timeout instance-attribute

timeout: float | None

Seconds to give each document. A document still being read when the time passes is stopped and reported as skipped. Enforced by reading in a worker process, so a run with a timeout always uses one.

extracted_text instance-attribute

extracted_text: bool

Keep the text read off each page. It is the document, so it is off by default.

offline_guard instance-attribute

offline_guard: bool

Block outbound sockets for the duration. On, and only off for a caller who knows their process needs the network while this runs.

progress instance-attribute

progress: Callable[[int, int, Path], None] | None

Called with (finished, total, path) as each document completes.

verify_with instance-attribute

verify_with: VisionModel | str | None

Read pages again with a vision model of your own, and report where it disagrees.

A callable taking a VisionPage and returning a VisionReading or the text, or a "vision:module:function" spec naming a factory for one. The page images go wherever that code sends them, and the report names the hosts. A callable keeps the run in one process; a spec crosses into workers. Nothing is verified by default.

verify_scope instance-attribute

verify_scope: Literal['flagged', 'all']

flagged, the default: the pages routing sent to vision, the pages with no usable reading, and the pages two readers disagreed about. all: every page.

complydoc.AuditReport dataclass

signal_weights class-attribute instance-attribute

signal_weights: dict[str, float] = field(
    default_factory=dict
)

Printed in the report whenever a score is shown.

config_masking class-attribute instance-attribute

config_masking: MaskingConfig | None = None

Echoed so the report can state how much of a value is shown.

overall class-attribute instance-attribute

overall: OverallReadiness | None = None

Global readiness: content, cost and exposure combined.

Both this and quick_wins are derived from a finished report, so their modules import this one. The annotations are resolved only by a type checker, which keeps the dependency one-way at runtime.

quick_wins class-attribute instance-attribute

quick_wins: list[QuickWin] = field(default_factory=list)

What to do next, ranked. See complydoc.report.quickwins.

loader class-attribute instance-attribute

loader: LoaderRun | None = None

Set when the documents came from an external loader.

loader_comparison class-attribute instance-attribute

loader_comparison: LoaderComparison | None = None

Set by compare_loaders. loader is then the baseline's run.

routing class-attribute instance-attribute

routing: RoutingSummary | None = None

Pages per route for the folder, and what that mix costs. See complydoc.report.routing.

verification class-attribute instance-attribute

verification: VerificationSummary | None = None

How many pages an independent vision read agreed with. None unless --verify.

to_pandas

to_pandas(table: str = 'documents') -> Any

One table of this report as a pandas DataFrame.

Table names are in complydoc.report.tables.TABLES. Requires the notebook extra.

complydoc.Change dataclass

area instance-attribute

area: str

documents, identifiers, metadata, hidden, readiness, signals, similarity, global, facts, loaders or limitations.

kind instance-attribute

kind: str

added, removed or changed.

complydoc.Chunk dataclass

One piece of a document's text, and what is known about it.

document instance-attribute

document: str

Path relative to the folder that was asked for.

part instance-attribute

part: int

1 unless the page was split to fit max_tokens.

token_fidelity instance-attribute

token_fidelity: str

'exact', 'approximate' (a real encoding, another provider's) or 'estimated'.

masked instance-attribute

masked: int

How many identifiers were covered over in this chunk.

masked_confirmed instance-attribute

masked_confirmed: int

How many of those passed a checksum.

The difference between the two is the part of the masking that is best effort. A chunk where they are equal had nothing guessed in it.

source instance-attribute

source: str

'native' where the text was on the page, 'ocr' where it was recognised.

complydoc.ChunkComparison dataclass

to_pandas

to_pandas() -> Any

One row per chunker. Requires the notebook extra.

complydoc.ChunkReport dataclass

repeated_identifiers class-attribute instance-attribute

repeated_identifiers: dict[str, int] = field(
    default_factory=dict
)

Identifiers found in more than one chunk, with the number of chunks.

retrieval class-attribute instance-attribute

retrieval: list[QuestionResult] = field(
    default_factory=list
)

One result per question, when questions were given.

retrieval_hit_rate property

retrieval_hit_rate: float | None

Share of questions retrieved within top_k. None without questions.

mean_reciprocal_rank property

mean_reciprocal_rank: float | None

Mean of 1/rank for questions retrieved within top_k, 0 for the rest.

to_pandas

to_pandas() -> Any

One row per chunk. Requires the notebook extra.

complydoc.ChunkStats dataclass

complydoc.CleanResult dataclass

What was written, and what was done to it.

masked class-attribute instance-attribute

masked: int = 0

Identifiers replaced by their masked form.

masked_confirmed class-attribute instance-attribute

masked_confirmed: int = 0

The subset of those that passed a checksum.

metadata_removed class-attribute instance-attribute

metadata_removed: list[str] = field(default_factory=list)

Metadata keys and parts taken out of the copy.

unscanned_categories class-attribute instance-attribute

unscanned_categories: dict[str, str] = field(
    default_factory=dict
)

Categories nothing was looked for, so none of that kind were masked.

changes class-attribute instance-attribute

changes: list[CleanChange] = field(default_factory=list)

Each identifier covered over, with where it was.

notes class-attribute instance-attribute

notes: list[str] = field(default_factory=list)

What the copy does not cover, in the caller's own terms.

skipped class-attribute instance-attribute

skipped: str | None = None

Set when no copy was written, with the reason.

complydoc.ContentFinding dataclass

A passage that is hidden from a reader, reads as an instruction to a model, or both.

visibility instance-attribute

visibility: str

visible, not_measured, suspected (one signal) or confirmed.

instruction instance-attribute

instruction: str

confirmed (decoded from hidden characters), pattern, model or none.

excerpt instance-attribute

excerpt: str

The passage, identifiers masked unless the run used reveal, cut at 240 characters.

score class-attribute instance-attribute

score: float | None = None

The registered classifier's score, when there is one.

in_loader_output class-attribute instance-attribute

in_loader_output: bool | None = None

For loader output: whether the loader's text contains this passage.

complydoc.Document dataclass

page_count_known class-attribute instance-attribute

page_count_known: bool = True

False for formats with no fixed pagination until they are rendered.

load_warnings class-attribute instance-attribute

load_warnings: list[str] = field(default_factory=list)

Non-fatal problems. These become entries in the report's limitations.

complydoc.DocumentFormat

Bases: StrEnum

OTHER class-attribute instance-attribute

OTHER = 'other'

For a third-party loader of a format complydoc does not know.

The registry is public, so a third party can teach complydoc a format without changing it. They need a name for what they are loading, and inventing enum members for formats we have never seen is not possible — so there is one to share. The reports group by this, so a folder of them appears together as "other".

complydoc.DocumentReport dataclass

routing class-attribute instance-attribute

routing: DocumentRouting | None = None

The route each page needs: its text layer, OCR, or a vision model.

previews class-attribute instance-attribute

previews: list[PagePreview] = field(default_factory=list)

Per-page wireframes. Geometry only — never document content.

extracted_text class-attribute instance-attribute

extracted_text: list[PageText] = field(default_factory=list)

The text itself. Only populated with --extracted-text: it is the document.

extractions class-attribute instance-attribute

extractions: list[ExtractorReading] = field(
    default_factory=list
)

One per extractor the run was asked for. The first is the one kept.

metadata_findings class-attribute instance-attribute

metadata_findings: list[MetadataFinding] = field(
    default_factory=list
)

Identifiers in the metadata a loader returned. Empty for files read directly.

content_findings class-attribute instance-attribute

content_findings: list[ContentFinding] = field(
    default_factory=list
)

Hidden passages and instruction-like text. See complydoc.hidden.

verification class-attribute instance-attribute

verification: DocumentVerification | None = None

Pages read again by a vision model. None unless the run used --verify.

visibility_checked class-attribute instance-attribute

visibility_checked: bool | None = None

Whether hidden text could be checked for. None when the scan did not run.

path_exposures class-attribute instance-attribute

path_exposures: list[str] = field(default_factory=list)

Metadata keys whose value is an absolute filesystem path.

Not an identifier category, and no detector would flag it, but a home directory path names the account it belongs to and the layout around it.

extractors_disagree property

extractors_disagree: bool

Whether the extractors read this document differently enough to say so.

Measured against the one whose output was kept. A tenth of the text is the line: below that the difference is line endings and whitespace, and reporting it would be noise on every document.

disagreement property

disagreement: str | None

The kind of disagreement between extractors, or None.

complydoc.Expectation

collect instance-attribute

collect = collect

Gather results instead of raising, so every check runs. Used by policies.

no_identifiers

no_identifiers(
    *,
    severity: str | None = None,
    evidence: str | None = None,
    categories: Iterable[str] | None = None,
) -> Expectation

No identifiers in text or metadata at or above severity and evidence.

no_hidden

no_hidden(*, severity: str = 'medium') -> Expectation

No hidden or instruction-like passages at or above severity.

readiness_at_least

readiness_at_least(score: float) -> Expectation

Every scored document has a readiness score of at least score.

facts_found

facts_found(
    facts: Iterable[Fact | str] | None = None,
    *,
    threshold: float = FUZZY_THRESHOLD,
) -> Expectation

Every fact found by every loader.

Without facts, uses the facts of a compare_loaders report.

no_network

no_network() -> Expectation

Nothing in the run reached the network: no loader, and no classifier.

The loader attempts were the whole of this check, which made it pass on a run that sent every judged passage to a hosted service — the one case where a gate asserting "no network" most needs to fail.

no_failures

no_failures() -> Expectation

No loader failed on a file, and no file was skipped.

no_regressions

no_regressions(
    baseline: AuditReport | str | PathLike[str],
    *,
    score_tolerance: float = 0.5,
) -> Expectation

Nothing worse than in baseline, a report or a path to its JSON.

complydoc.Extraction dataclass

One page as one extractor read it.

raw_chars class-attribute instance-attribute

raw_chars: str = ''

Characters before unicode normalisation, where the extractor exposes them.

Empty when it does not: the garbled-character signal needs un-normalised text and reports as not measured without it.

tables_searched class-attribute instance-attribute

tables_searched: bool = False

False when this extractor cannot look for tables at all, which is not the same as looking and finding none.

coverage_pct

coverage_pct(width: float, height: float) -> float | None

Share of the page covered by text boxes, or None if none were returned.

A reader that returns text without geometry has no coverage measurement.

complydoc.ExtractionWarning dataclass

Something the caller needs to know before using the text.

hides_content property

hides_content: bool

Whether this warning means text is missing from the result.

complydoc.Fact dataclass

A passage a document is expected to contain.

document class-attribute instance-attribute

document: str | None = None

File name or relative path to check. None checks every document.

complydoc.FactCheck dataclass

Whether one expected fact appears in the text of each loader.

document instance-attribute

document: str | None

The document the fact was checked in, or None for every document.

found instance-attribute

found: dict[str, str | None]

Loader name to exact, fuzzy, or None.

scores instance-attribute

scores: dict[str, float]

Loader name to the best similarity found, from 0 to 1.

documents instance-attribute

documents: dict[str, str | None]

Loader name to the document the fact was found in.

nearest class-attribute instance-attribute

nearest: dict[str, str | None] = field(default_factory=dict)

Loader name to the passage that came closest, where the fact was not found exactly.

What a missing fact looks like in that loader's text, which is usually the reason it went missing.

complydoc.FactLocation dataclass

status instance-attribute

status: str

whole when one chunk contains it, split when only the joined document text does, missing otherwise.

complydoc.IdentifierDifference dataclass

An identifier in some loaders' output and not in others'.

Matched by where it was found, its category and its masked value, so the same identifier read by two loaders is one row. Metadata findings are matched regardless of key name, because loaders spell the same field differently: producer in one, Producer in another.

value instance-attribute

value: str

Masked, unless the run used reveal.

location instance-attribute

location: str

text or metadata.

keys instance-attribute

keys: list[str]

The metadata keys it was found under. Empty for text.

complydoc.IngestOptions dataclass

ocr class-attribute instance-attribute

ocr: bool = False

Run local OCR on pages with no usable text layer.

ocr_min_chars class-attribute instance-attribute

ocr_min_chars: int = 40

Below this many native characters, a page counts as having no text layer.

render_dpi class-attribute instance-attribute

render_dpi: int = 150

Resolution used when rasterising a page for OCR or skew measurement.

max_render_pages class-attribute instance-attribute

max_render_pages: int = 50

Cap on how many pages of one document are rasterised, to bound memory.

extractor class-attribute instance-attribute

extractor: str = 'pdfplumber'

Which extractor's output the report is built from.

compare_extractors class-attribute instance-attribute

compare_extractors: tuple[str, ...] = ()

Others to run alongside, for comparison only. They never change a finding.

compare_engines class-attribute instance-attribute

compare_engines: tuple[str, ...] = ()

OCR engines to read every rasterised page with, beside the one in use.

keep_readings class-attribute instance-attribute

keep_readings: bool = False

Whether to keep each reader's text for the page.

password class-attribute instance-attribute

password: str = ''

Tried on encrypted files before falling back to an empty password.

ocr_compare class-attribute instance-attribute

ocr_compare: bool = False

Also OCR pages that already have a text layer, so the two can be compared.

render_all_pages class-attribute instance-attribute

render_all_pages: bool = False

Rasterise every page, including pages no signal needs.

Set when the report is going to show the page next to what was extracted from it. Off by default: rasterising costs time and memory, and the default report carries no page images.

complydoc.InspectedChunk dataclass

document instance-attribute

document: str | None

The source file named in the chunk's metadata.

identifiers instance-attribute

identifiers: list[str]

Identifiers in the chunk, as label: masked value.

hidden instance-attribute

hidden: int

Hidden or instruction-like passages of medium severity or above.

preview instance-attribute

preview: str

The start of the chunk with identifiers masked.

complydoc.LoaderComparison dataclass

Where several loaders' output differed, measured against the first.

metadata_keys class-attribute instance-attribute

metadata_keys: dict[str, list[str]] = field(
    default_factory=dict
)

Keys not returned by every loader, matched ignoring case, and which returned them.

documents class-attribute instance-attribute

documents: dict[str, list[str]] = field(
    default_factory=dict
)

Documents not returned by every loader, and which loaders returned them.

facts class-attribute instance-attribute

facts: list[FactCheck] = field(default_factory=list)

Expected facts, checked against every loader's text.

recommended class-attribute instance-attribute

recommended: str | None = None

The loader to use, where the run could tell. None when it could not.

verdict class-attribute instance-attribute

verdict: str = ''

What decided the recommendation, or what stopped it being decided.

ranked class-attribute instance-attribute

ranked: list[str] = field(default_factory=list)

Every loader, best first, by what the run could measure.

complydoc.LoaderRun dataclass

What an external loader did when complydoc ran it.

seconds instance-attribute

seconds: float | None

None when documents were passed in already loaded.

network_attempts class-attribute instance-attribute

network_attempts: list[str] = field(default_factory=list)

Connections the loader tried to open: refused by the guard, or made, when network_allowed is true.

metadata_keys class-attribute instance-attribute

metadata_keys: list[str] = field(default_factory=list)

Every metadata key the loader returned, across all documents.

failures class-attribute instance-attribute

failures: dict[str, str] = field(default_factory=dict)

Files the loader raised on, with the error, when it ran over several files.

cached_files class-attribute instance-attribute

cached_files: int = 0

Files whose output came from the cache instead of the loader.

network_allowed class-attribute instance-attribute

network_allowed: bool = False

The caller passed allow_network=True, so the loader's connections went through. complydoc's own processing stays behind the guard either way.

tags class-attribute instance-attribute

tags: list[str] = field(default_factory=list)

The framework and library the loader comes from, such as LangChain and pypdf.

complydoc.LoaderSummary dataclass

One loader's totals, in a comparison of several.

documents_with_paths instance-attribute

documents_with_paths: int

Documents with at least one metadata key holding an absolute path.

failures class-attribute instance-attribute

failures: dict[str, str] = field(default_factory=dict)

Files the loader raised on, with the error.

facts_found class-attribute instance-attribute

facts_found: int | None = None

Expected facts found in this loader's text, when facts were given.

parser_usd class-attribute instance-attribute

parser_usd: float | None = None

Estimated parser cost for these pages, from parsers in pricing.yaml.

tags class-attribute instance-attribute

tags: list[str] = field(default_factory=list)

The framework and library the loader comes from, such as LangChain and pypdf.

complydoc.MaskedText dataclass

A string with its identifiers replaced by mask characters.

masked instance-attribute

masked: int

Identifiers replaced.

masked_confirmed instance-attribute

masked_confirmed: int

Of those, how many passed a checksum.

complete property

complete: bool

False when a category could not be scanned, so none of its values were masked.

complydoc.MetadataFinding dataclass

An identifier found in a document's metadata.

Loaders attach metadata to every document they return, and it is usually stored beside the content — in a vector store, next to each chunk — so an identifier there travels exactly as far as one in the text.

significant property

significant: bool

Whether this finding raises limitations and quick wins.

A low-severity category found by the name model is excluded. Loaders put the producing software in metadata — "ReportLab PDF Library", "Microsoft Word" — and the model labels it an organisation, which would otherwise flag every PDF. It stays in the list; it does not become a limitation or a quick win on its own.

complydoc.Page dataclass

number instance-attribute

number: int

1-indexed.

ocr_text class-attribute instance-attribute

ocr_text: str = ''

What OCR read, kept separately from text.

Normally OCR only runs where there is no text layer, and its output becomes text. With ocr_compare it runs on every page as well, so the text layer and the recognised text can be put side by side — which is how you tell a document that extracts badly from an extractor that reads it badly.

ocr_confidence class-attribute instance-attribute

ocr_confidence: float | None = None

The engine's mean confidence in what it read, 0 to 1. None if it did not run.

ocr_seconds class-attribute instance-attribute

ocr_seconds: float | None = None

How long OCR took on this page, on the machine that ran it. None if it did not run.

raw_chars class-attribute instance-attribute

raw_chars: str = ''

Page characters as stored, before any unicode normalisation.

text comes from the extractor's own text assembly, which NFKC-normalises — turning a fi ligature into two plain letters. That is usually helpful, but it destroys exactly the evidence the garbled-character signal needs, so the un-normalised characters are kept alongside. Word spacing is absent here, so this is only useful for character-level questions.

extractions class-attribute instance-attribute

extractions: list[ExtractionSummary] = field(
    default_factory=list
)

One per extractor asked for, including the one whose output was kept.

readings class-attribute instance-attribute

readings: dict[str, str] = field(default_factory=dict)

What each extractor and OCR engine made of this page, by name.

Only populated for the readers a run was asked to compare, and only when the run is keeping text at all. It is the page's words several times over, so it is the largest thing a comparison adds to a report.

raster class-attribute instance-attribute

raster: Image | None = None

Populated only for pages that need to be looked at as pixels.

size_key property

size_key: tuple[int, int]

Rounded page size, for counting distinct sizes within one document.

estimated_dpi

estimated_dpi() -> float | None

Effective scan resolution, from the largest embedded image on the page.

Only meaningful where the page really is a scan; a page whose images are small logos will report a number that means nothing, so callers check image coverage first.

complydoc.PageSource dataclass

The handles a page can be read through.

One per library, opened once by the loader. An extractor takes the handle it understands and ignores the rest, so adding a third does not mean opening the file a third time for the two that were already there.

pypdf class-attribute instance-attribute

pypdf: Any = None

The reader the loader already opened, decrypted if the file was.

number class-attribute instance-attribute

number: int = 1

Which page this is, one-based, for readers that index a whole document.

complydoc.Question dataclass

A question and a passage that answers it.

fact instance-attribute

fact: str

A passage the answering chunk contains, matched as expected facts are.

document class-attribute instance-attribute

document: str | None = None

File name or relative path holding the answer. None accepts any document.

complydoc.QuestionResult dataclass

status instance-attribute

status: str

retrieved, ranked_low, split or missing.

rank instance-attribute

rank: int | None

Rank of the best-placed chunk holding the fact, from 1. None when no such chunk shares a word with the question.

answer_chunks instance-attribute

answer_chunks: list[int]

Indexes of the chunks holding the fact.

top_chunks instance-attribute

top_chunks: list[int]

Indexes of the top_k best-ranked chunks, best first.

complydoc.Recognised dataclass

What an engine read, and how sure it was.

An engine reports a confidence for every box it recognises. Throwing those away would leave OCR text asserted with the same authority as a native text layer, which it has not earned.

complydoc.Rect dataclass

complydoc.ReportDiff dataclass

to_pandas

to_pandas() -> Any

The changes as a DataFrame. Requires the notebook extra.

summary

summary() -> str

One line per change.

complydoc.SkipRecord dataclass

A file complydoc could not open, or could not finish. Reported; the run continues.

complydoc.TextBlock dataclass

complydoc.TextResult dataclass

Everything read, in order, with what could not be read alongside it.

text property

text: str

Every chunk joined, for the common case of wanting the lot.

complete property

complete: bool

Whether everything in the folder reached this result.

False when a file or a page could not be read.

all_categories_scanned property

all_categories_scanned: bool

Whether every configured identifier category ran.

True means no category was skipped. Categories found by a model can still miss values; MASKING_BEST_EFFORT says so every time masking runs.

guaranteed property

guaranteed: list[Chunk]

The chunks whose identifiers were all confirmed by a checksum.

Empty unless mask ran. Use it where a wrong answer is expensive enough that best effort is not good enough — and read all_categories_scanned first.

complydoc.TextScan dataclass

Identifiers found in a string.

unscanned class-attribute instance-attribute

unscanned: dict[str, str] = field(default_factory=dict)

Categories that could not be scanned, with the reason.

complydoc.VisionModel

Bases: Protocol

Anything called with a page that returns what it read.

complydoc.VisionPage dataclass

One page, rendered, as the model is given it.

document instance-attribute

document: str

The file's name, for a model that logs what it was sent.

number instance-attribute

number: int

1-indexed.

image instance-attribute

image: bytes

The page as an image, encoded as media_type.

complydoc.VisionReading dataclass

What a vision model read off one page.

input_tokens class-attribute instance-attribute

input_tokens: int | None = None

The provider's own count, from the response. Makes the cost actual.

usd class-attribute instance-attribute

usd: float | None = None

What the call cost, where the caller already knows. Taken as given.

model class-attribute instance-attribute

model: str | None = None

The model that answered, where it differs from the one the reader named.

complydoc.clean_document

clean_document(
    path: str | Path,
    out_dir: str | Path,
    config: Config | None = None,
    *,
    rasterise: bool = False,
) -> CleanResult

Write a safe copy of path into out_dir, and say what was done to it.

rasterise applies to PDFs only: each page is rendered to an image and the file rebuilt from those, so the text layer does not survive.

complydoc.sha256_of

sha256_of(path: Path) -> str