Skip to main content

Production-grade document-to-Markdown conversion library with hexagonal architecture.

Project description

CyberDocExtractor

PyPI version CI Security Docs Coverage Tests Python License: MIT Code style: ruff Typed: mypy strict

Production-grade Python library for converting PDF, DOCX, DOC, XLSX, XLS, and CSV documents to Markdown. Multiple precision levels, automatic extractor fallback, LLM-assisted image descriptions, and a strict hexagonal core.

pip install cyberdocextractor==0.1.1

Why another document extractor?

Every upstream library (Docling, PyMuPDF, pdfplumber, python-docx, openpyxl, xlrd, …) has its own model, error semantics, and quirks. CyberDocExtractor wraps them behind a single typed domain model:

  • Hexagonal architecture — the domain doesn't know what PyMuPDF is. Boundaries are enforced by import-linter in CI (three contracts, kept on every PR).
  • Pluggable extractors — swap, reorder, or add adapters without touching the core. Heavy dependencies are lazy-imported, so installing with no extras still works.
  • Automatic fallback — if the preferred extractor fails, the next candidate in the policy chain is tried. A corrupt page doesn't abort a batch.
  • Deterministic quality scoring — every conversion reports a 0.0 – 1.0 score, so downstream RAG / ETL can gate on confidence.
  • Immutable value objects everywhere — frozen, slotted dataclasses with invariants enforced in __post_init__; metadata maps wrapped in MappingProxyType so templates can't corrupt pipeline state.
  • Strict CI — mypy strict, ruff with pydocstyle, import-linter architectural contracts, 90% coverage floor (currently 97%), matrix tests on Linux + macOS × Python 3.11 / 3.12 / 3.13.

Installation

Command What you get
pip install cyberdocextractor Core + CSV (stdlib)
pip install 'cyberdocextractor[pdf]' + PyMuPDF / pymupdf4llm / pdfplumber (PDF, 3 precision tiers)
pip install 'cyberdocextractor[doc]' + Docling (PDF / DOCX / XLSX at HIGHEST_QUALITY; also powers DOCX)
pip install 'cyberdocextractor[docx]' + python-docx + defusedxml (needed by the .doc adapter)
pip install 'cyberdocextractor[xlsx]' + openpyxl (XLSX) + xlrd (legacy XLS) + defusedxml
pip install 'cyberdocextractor[llm]' + httpx + Pillow (LLM image descriptions)
pip install 'cyberdocextractor[cli]' + Typer + Rich (cyberdoc command)
pip install 'cyberdocextractor[all]' Everything above

The .doc adapter additionally requires LibreOffice on your PATH (soffice or libreoffice) — the adapter shells out for the CFBF → DOCX conversion, then parses the result with python-docx.

30-second Python

from pathlib import Path
from cyberdocextractor import PrecisionLevel, build_pipeline, load_document

pipeline = build_pipeline()

doc = load_document(Path("report.pdf"), precision=PrecisionLevel.BALANCED)
report = pipeline.convert(doc)

print(report.markdown.text)
print(f"extractor={report.extractor}")
print(f"attempted={list(report.attempted)}")
print(f"quality={report.markdown.quality_score:.2f}")

30-second CLI

# Single document to stdout (or -o FILE)
cyberdoc convert report.pdf --show-score

# Batch with glob + precision override
cyberdoc batch inputs/ outputs/ --pattern '*.pdf' --level 3

# Which adapters are available on this machine?
cyberdoc status

# Size / MIME / auto-selected precision (no conversion)
cyberdoc info report.pdf

# List bundled Jinja2 templates
cyberdoc templates

cyberdoc version
Command Purpose
convert Convert one document. Flags: --level {1,2,3,4}, --template NAME, --mime MIME, --output FILE, --show-score, --no-fallback.
batch Walk a directory with a glob pattern and write mirrored .md files. Failures are captured, not raised — exit 1 if any file failed.
status Rich table of extractor availability per MIME type (PDF / DOCX / DOC / XLSX / XLS / CSV).
info Print size, MIME, classification, and the precision that would be auto-selected.
templates List available Jinja2 templates.
version Print the installed package version.

Full CLI reference.

Architecture

Four layers, one set of import rules, enforced by import-linter in CI:

flowchart TB
    CLI["cli — Typer entrypoints"]
    APP["app — ConversionPipeline + stages"]
    INFRA["infra — PyMuPDF, pdfplumber, Docling, openpyxl, xlrd, Jinja2, httpx, LibreOffice"]
    DOMAIN["domain — pure value objects, ports, rules"]

    CLI --> APP
    CLI --> INFRA
    CLI --> DOMAIN
    APP --> DOMAIN
    INFRA --> APP
    INFRA --> DOMAIN

    classDef pure fill:#eef,stroke:#448,stroke-width:2px;
    classDef app fill:#efe,stroke:#484,stroke-width:2px;
    classDef infra fill:#fee,stroke:#844,stroke-width:2px;
    classDef cli fill:#fef,stroke:#848,stroke-width:2px;

    class DOMAIN pure;
    class APP app;
    class INFRA infra;
    class CLI cli;
  • Domain — pure value objects (Document, Block, NormalizedDoc, Markdown, ExtractionOutcome, TemplateContext, ConversionReport), enums, Protocol ports, typed errors, pure rules. Zero external dependencies.
  • ApplicationConversionPipeline + five composable stages, loader + batch helpers, default Clock / Scorer.
  • Infrastructure — one lazy-imported adapter per upstream library.
  • CLI — Typer commands that parse arguments and delegate.

Three import-linter contracts keep the stack honest on every PR:

  1. Hexagonal layers (layered stack).
  2. Domain is pure — domain cannot import from app, infra, or cli.
  3. App depends only on domain — app cannot import infra or cli.

Conversion pipeline

flowchart LR
    Input[Document] --> Ex[ExtractionStage]
    Ex --> Meta[MetadataStage]
    Meta --> Img[ImageEnrichmentStage]
    Img --> Tab[TableProfilingStage]
    Tab --> Ren[RenderingStage]
    Ren --> Report[ConversionReport]
  • ExtractionStage walks the policy-selected chain with automatic fallback; adapters wrap failures in ExtractionOutcome.fail rather than raising.
  • MetadataStage, ImageEnrichmentStage, TableProfilingStage are defensive — individual probe / describer / profiler failures are logged and skipped, never allowed to fail the conversion.
  • RenderingStage wraps Jinja2 errors in RenderingError and scores the final Markdown.

Full deep-dive: docs/architecture/pipeline.md.

Precision levels

Level Name Typical extractor Trade-off
1 FASTEST pymupdf-chunked speed > fidelity; no layout analysis
2 BALANCED (default) pymupdf4llm good text + tables at moderate speed
3 TABLE_OPTIMIZED pdfplumber best for structured tables
4 HIGHEST_QUALITY Docling OCR, images, full layout; slowest

When you pass BALANCED (the default), the policy auto-selects based on document size:

  • < 2 MiBHIGHEST_QUALITY (small files are cheap to process at full fidelity).
  • > 20 MiBFASTEST (archival scans need throughput).
  • otherwise → stays at BALANCED.

document.metadata["has_tables"] = True promotes to TABLE_OPTIMIZED at any size. Passing any precision other than BALANCED bypasses the auto-resolution — your choice is respected as-is.

Rationale in ADR 0005; disable via build_pipeline(size_aware_policy=False).

Format support

Format Extension Extractor(s) Required extras
CSV .csv csv-stdlib none
PDF .pdf pymupdf-chunked, pymupdf4llm, pdfplumber, docling [pdf] (one of the first three) or [doc] (Docling)
DOCX .docx docling [doc]
DOC (legacy) .doc libreoffice-doc [docx] plus LibreOffice on PATH
XLSX .xlsx openpyxl, docling [xlsx] or [doc]
XLS (legacy) .xls xlrd [xlsx]

cyberdoc status shows the matrix for the adapters actually available in your environment.

Releases

Version Highlights
0.1.1 Added XlrdExtractor (legacy .xls) and LibreOfficeDocExtractor (legacy .doc via soffice). CLI status table surfaces DOC and XLS columns.
0.1.0 First public release. Full hexagonal core, six extractors, Jinja2 renderer, heuristic scorer, PDF + Office metadata probes, OpenAI-compatible LLM image describer, Typer CLI.

Changelog: docs/changelog.md. Roadmap (including known limitations and post-1.0 plans): docs/roadmap.md.

Documentation

Development

Prerequisites: Python 3.11+, uv, just.

git clone https://github.com/CyberdyneCorp/CyberDocExtractor.git
cd CyberDocExtractor
just bootstrap    # uv sync --all-extras --group dev --group docs + pre-commit

just check        # format + lint + mypy + import-linter + tests
just test-unit    # unit tests only
just test-bdd     # pytest-bdd scenarios only
just docs-serve   # mkdocs-material live preview

See CONTRIBUTING.md for the full contribution workflow.

Security

See SECURITY.md for the responsible-disclosure policy. Highlights:

  • XML parsing uses defusedxml by default (Office metadata probes).
  • Jinja2 environments are sandboxed; autoescape=False because the output format is Markdown.
  • Dependencies scanned weekly (Bandit, pip-audit, TruffleHog).

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cyberdocextractor-0.1.2.tar.gz (46.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cyberdocextractor-0.1.2-py3-none-any.whl (69.4 kB view details)

Uploaded Python 3

File details

Details for the file cyberdocextractor-0.1.2.tar.gz.

File metadata

  • Download URL: cyberdocextractor-0.1.2.tar.gz
  • Upload date:
  • Size: 46.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for cyberdocextractor-0.1.2.tar.gz
Algorithm Hash digest
SHA256 8331cf34b497655ac09f890f54cfb120270585e4aa5f6200e9975015f37a4478
MD5 2a826f14cf8f4762e4edc93bd7f75fc7
BLAKE2b-256 792ceb8284b2e6a6edc594d39aea89633b51ba10fee8a3be120045a062b487f4

See more details on using hashes here.

File details

Details for the file cyberdocextractor-0.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for cyberdocextractor-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 429e7959ce8d7c16c477638b276c7c1660377ad726f1e3ab3eb309442f1fb04d
MD5 bb8573fbfa509f4a5fa29db597677b0e
BLAKE2b-256 cf1b689309f68f62dc08dc4f88e4efa3bd4384c43689b83f4c870efaacbba269

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page