Rust port of docling (docling.rs): convert PDF/DOCX/HTML/... to Markdown or docling JSON. Python bindings.
Project description
docling-py — Python bindings (PyO3)
A strangler-fig drop-in for Python docling's common conversion path,
backed by the Rust docling.rs engine:
same call shape, no torch, ~4× faster PDF conversion at a fraction of the
memory (see PDF_PERFORMANCE.md).
# was: from docling.document_converter import DocumentConverter
from docling_rs import DocumentConverter
result = DocumentConverter().convert("document.pdf")
print(result.document.export_to_markdown())
data = result.document.export_to_dict() # docling-core JSON wire format (schema 1.10.0)
Only the document processor is Rust. The engine parses the input and returns
docling-core's JSON wire format; this package validates it into a genuine
docling_core.types.doc.DoclingDocument.
So result.document is the docling object — export_to_markdown(),
export_to_dict(), export_to_doctags(), the serializers, and the
chunkers are docling's own
Python code, unchanged. docling-core is a runtime dependency; nothing else from
docling is required for the declarative path.
Status: experimental. The PyPI distribution name is
docling-rs. Releases are cut manually (like the npm package) via thepypi-publishworkflow — see Publishing below. The crate is intentionally outside the repo's Cargo workspace and its crates.io publish flow. For development, build and install locally as shown next.
Try it locally
Needs a Rust toolchain (1.82+) and Python ≥ 3.9.
cd crates/docling-py
# 1. Build + install into the CURRENT virtualenv (create one first):
python -m venv .venv && source .venv/bin/activate
pip install maturin
maturin develop --release # compiles the Rust engine, installs `docling.rs`
# 2. One-time model download (~700 MB → ~/.cache/docling.rs), pure Python —
# fetched from the repo's models-v1 GitHub release, like docling fetches
# its artifacts. Declarative formats (DOCX/HTML/XLSX/…) skip this entirely.
python -c "import docling_rs; docling_rs.download_models()"
# 3. Convert:
python - <<'PY'
from docling_rs import DocumentConverter
conv = DocumentConverter()
result = conv.convert("../../tests/data/pdf/sources/2305.03393v1-pg9.pdf")
print(result.status) # "success"
print(result.document.export_to_markdown()[:400])
PY
API surface (docling-shaped)
| docling.rs | docling counterpart | notes |
|---|---|---|
DocumentConverter(format_options=None, *, allowed_formats=None, do_ocr=True, do_table_structure=True, fetch_images=False, use_web_browser=False, artifacts_path=None) |
DocumentConverter(allowed_formats=…, format_options=…) |
Pass {InputFormat.PDF: PdfFormatOption(pipeline_options=PdfPipelineOptions(…))} or the shorthand kwargs; allowed_formats restricts conversion; artifacts_path overrides the model cache dir. |
.convert(path | DocumentStream) -> ConversionResult |
.convert(source) |
str / pathlib.Path / DocumentStream. Releases the GIL during conversion. |
.convert_all(sources, raises_on_error=True) -> Iterator[ConversionResult] |
same | lazily converts many sources; raises_on_error=False yields a failure result instead of raising |
.initialize_pipeline(format=None) |
same | pre-loads the PDF/image ML models so the first conversion isn't slow and later PDFs reuse the warm pipeline (no-op for non-ML formats; needs the models available) |
.convert_bytes(name, data) |
DocumentStream |
extension of name drives format detection |
InputFormat, PdfPipelineOptions, PdfFormatOption, AcceleratorOptions, TableFormerMode, DocumentStream, ImageRefMode |
same modules | docling-shaped config re-exported from docling_rs (see below) |
ConversionError |
docling.exceptions.ConversionError |
raised on a failed conversion; caught by convert_all(..., raises_on_error=False) |
result.status / result.document / result.input.file |
same | .status is a ConversionStatus str-enum ("success" / "partial_success" / "failure"); .document is a genuine docling_core DoclingDocument |
document.export_to_markdown(...) |
same | docling-core's own method — all of docling's params (image_placeholder, page_break_placeholder, …) apply |
document.export_to_dict() / export_to_json() / export_to_doctags() |
same | docling-core's own serializers over the wire format |
document.save_as_markdown(p) / save_as_json(p) / chunkers |
same | anything docling_core offers on a DoclingDocument works, since it is one |
docling_rs.download_models() |
docling-tools models download |
idempotent; ~/.cache/docling.rs or $DOCLING_RS_CACHE_DIR; INT8 models fetched when hosted and preferred automatically (DOCLING_RS_FP32=1 opts out) |
Model/env resolution order: explicit DOCLING_* env vars → the cache dir set
by ensure_env() (called by the constructor) → the process CWD (models/,
.pdfium/, matching the CLI). pdfium is Linux x64 from the release; on other
platforms set PDFIUM_DYNAMIC_LIB_PATH to a local build.
Configuration (docling-shaped)
docling_rs re-exports docling-shaped config objects — same names and fields, so
docling code reads unchanged:
from docling_rs import DocumentConverter, InputFormat, PdfFormatOption, PdfPipelineOptions, AcceleratorOptions
opts = PdfPipelineOptions(
do_ocr=False, # skip OCR on scanned pages
do_table_structure=True, # TableFormer table recovery
accelerator_options=AcceleratorOptions(num_threads=4),
)
conv = DocumentConverter(format_options={InputFormat.PDF: PdfFormatOption(pipeline_options=opts)})
# shorthand: DocumentConverter(do_ocr=False, do_table_structure=True)
The Rust engine acts on do_ocr, do_table_structure, and
accelerator_options.num_threads (→ ONNX Runtime intra-op threads via
DOCLING_RS_PDF_THREADS). The remaining PdfPipelineOptions fields
(images_scale, generate_page_images, table_structure_options.mode, …) are
accepted for API compatibility but do not change the pipeline. InputFormat,
DocumentStream and ImageRefMode are re-exported too (the last straight from
docling_core, for export_to_markdown(image_mode=…)). A GPU
accelerator_options.device (CUDA/MPS) is accepted but warns and falls back
to CPU — the engine runs ONNX Runtime on the CPU execution provider.
Not covered (yet)
VLM/enrichment pipelines, GPU accelerator devices (the engine is ONNX Runtime on
CPU), and per-format backend selection. Chunkers are available — the
returned object is a real docling_core DoclingDocument, so
docling_core.transforms.chunker's HierarchicalChunker / HybridChunker
operate on it directly (install docling-core's own extras for those:
pip install "docling-core[chunking]"). The document carries rendered text for
inline formatting rather than structured formatting fields — see
MIGRATION.md §4 for the documented divergences.
Publishing
Releases are manual, mirroring the npm package: the
pypi-publish GitHub Actions workflow
(workflow_dispatch) builds an abi3 wheel per platform (Linux x86-64/arm64 as
manylinux_2_28, Windows x86-64 — one wheel covers every Python ≥ 3.9) plus an
sdist, and uploads them to PyPI.
# From the Actions tab, or:
gh workflow run pypi-publish.yml # version from pyproject.toml
gh workflow run pypi-publish.yml -f version=0.16.0
No secrets: it publishes via PyPI Trusted Publishing (OIDC), like
docling-core — no API token is stored or rotated. This requires a one-time
setup on PyPI by the project owner (below); re-runs are idempotent
(skip-existing). macOS wheels are omitted (no hosted runners here); macOS users
install the sdist, which compiles from source. The ONNX runtime is bundled in the
wheel; pdfium is fetched at runtime by download_models().
First-time PyPI setup (project owner)
Trusted Publishing lets this repo's workflow upload to PyPI without any password
or API token — GitHub mints a short-lived OIDC token per run and PyPI verifies it
against a trusted publisher you register once. Until that publisher exists, the
publish job fails with invalid-publisher: valid token, but no corresponding publisher.
Because the docling-rs project does not exist on PyPI yet, register a pending
publisher (it both authorizes the workflow and lets the first run create the
project):
-
Sign in to PyPI as the account that will own
docling-rs, then open https://pypi.org/manage/account/publishing/. -
Under “Add a new pending publisher”, choose GitHub and fill in exactly these values:
Field Value PyPI Project Name docling-rsOwner docling-projectRepository name docling.rsWorkflow name pypi-publish.ymlEnvironment name pypi -
Click Add. Then re-run the pypi publish workflow (Actions tab → Run workflow) — the
publishjob will now succeed and create the project on its first upload.
Notes:
- The Git branch does not matter: PyPI matches on repository + workflow + environment, not the branch, so publishing works from any branch once the publisher is registered.
- Environment name must be
pypi— it has to match theenvironment: pypithepublishjob runs in. - After the first successful publish the project exists; the pending publisher automatically becomes a regular trusted publisher (manage it later at Project → Manage → Publishing). To rotate/add publishers there, use the same five values above.
- To rehearse without touching production PyPI, register the equivalent pending
publisher on TestPyPI (https://test.pypi.org/manage/account/publishing/)
and point the workflow's upload at
https://test.pypi.org/legacy/.
Test the release build locally
Reproduce what CI does — build the wheel + sdist and verify both install and run — before (or instead of) triggering the workflow. Needs a Rust toolchain and Python ≥ 3.9.
cd crates/docling-py
python -m venv .venv && source .venv/bin/activate
pip install maturin
# 1. Build the same two artifacts the workflow builds.
maturin build --release --out dist # dist/docling_rs-<v>-cp39-abi3-<platform>.whl
maturin sdist --out dist # dist/docling_rs-<v>.tar.gz (vendors all crates)
# 2. Smoke-test the WHEEL in a clean env — pip pulls docling-core from the
# wheel's declared dependency, exactly as an end user would get it.
python -m venv /tmp/wheel-test
/tmp/wheel-test/bin/pip install dist/docling_rs-*.whl
/tmp/wheel-test/bin/python - <<'PY'
from docling_rs import DocumentConverter
r = DocumentConverter().convert("../../tests/data/html/sources/hyperlink_03.html")
assert r.status == "success"
assert type(r.document).__module__.startswith("docling_core") # the real DoclingDocument
print("wheel OK:", len(r.document.export_to_markdown()), "md chars")
PY
# 3. Verify the SDIST is self-contained: pip compiles the Rust engine from source
# (this is the exact unpack-and-build path cibuildwheel runs in the manylinux
# containers, so a green result here means the CI wheel build will work too).
python -m venv /tmp/sdist-test
/tmp/sdist-test/bin/pip install dist/docling_rs-*.tar.gz
/tmp/sdist-test/bin/python -c "import docling_rs; print('sdist build OK')"
# 4. Run the declarative-path test suite (no ML models needed).
pip install pytest docling-core
pytest tests/
To exercise the full manylinux wheel build (what pypa/cibuildwheel runs) you
need Docker; with a daemon available:
pipx run cibuildwheel==2.21.3 --platform linux --output-dir wheelhouse .
# env: CIBW_BUILD=cp39-* CIBW_SKIP=*-musllinux* CIBW_BEFORE_ALL_LINUX="curl … rustup … -y"
An optional final rehearsal uploads to TestPyPI (needs a TestPyPI token or a
pending publisher there): pip install twine && twine upload --repository testpypi dist/*.
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
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file docling_rs-0.15.1.tar.gz.
File metadata
- Download URL: docling_rs-0.15.1.tar.gz
- Upload date:
- Size: 354.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5498a2d65eaefcfd16be5ed6e23b1718fbd7067051fe5876df6ffe43a3552263
|
|
| MD5 |
59df4997747fb7c2de90574d23009439
|
|
| BLAKE2b-256 |
9949d7441dd6b7d259dfd813c5fbef0b2221b1ceeffc7562d9598ea705b10b4c
|
Provenance
The following attestation bundles were made for docling_rs-0.15.1.tar.gz:
Publisher:
pypi-publish.yml on docling-project/docling.rs
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
docling_rs-0.15.1.tar.gz -
Subject digest:
5498a2d65eaefcfd16be5ed6e23b1718fbd7067051fe5876df6ffe43a3552263 - Sigstore transparency entry: 2160686539
- Sigstore integration time:
-
Permalink:
docling-project/docling.rs@98f5326c6019d3517aca086bb267de5c6bf22f25 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/docling-project
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@98f5326c6019d3517aca086bb267de5c6bf22f25 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file docling_rs-0.15.1-cp39-abi3-win_amd64.whl.
File metadata
- Download URL: docling_rs-0.15.1-cp39-abi3-win_amd64.whl
- Upload date:
- Size: 14.4 MB
- Tags: CPython 3.9+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5186655baa013c4cfac02a30fab50b7fec9bec68062c925c34fb7c2f5054bac8
|
|
| MD5 |
223a05957709401f963659ccd43937ac
|
|
| BLAKE2b-256 |
004593a97827958fd92fae801ccb290f0e0736d537806ad276835c6c0ebddc70
|
Provenance
The following attestation bundles were made for docling_rs-0.15.1-cp39-abi3-win_amd64.whl:
Publisher:
pypi-publish.yml on docling-project/docling.rs
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
docling_rs-0.15.1-cp39-abi3-win_amd64.whl -
Subject digest:
5186655baa013c4cfac02a30fab50b7fec9bec68062c925c34fb7c2f5054bac8 - Sigstore transparency entry: 2160687768
- Sigstore integration time:
-
Permalink:
docling-project/docling.rs@98f5326c6019d3517aca086bb267de5c6bf22f25 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/docling-project
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@98f5326c6019d3517aca086bb267de5c6bf22f25 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file docling_rs-0.15.1-cp39-abi3-manylinux_2_28_x86_64.whl.
File metadata
- Download URL: docling_rs-0.15.1-cp39-abi3-manylinux_2_28_x86_64.whl
- Upload date:
- Size: 16.5 MB
- Tags: CPython 3.9+, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
73f6e3336cf897944d868b60b099c092abcb8e92d37b13d016c59c13a7822266
|
|
| MD5 |
0b71f997ffb4517495018ad4d06f1f3b
|
|
| BLAKE2b-256 |
246e4fd5c5d96960ffa449e156496896db7b854d1adeb3c4705ddf28fcdd2b7c
|
Provenance
The following attestation bundles were made for docling_rs-0.15.1-cp39-abi3-manylinux_2_28_x86_64.whl:
Publisher:
pypi-publish.yml on docling-project/docling.rs
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
docling_rs-0.15.1-cp39-abi3-manylinux_2_28_x86_64.whl -
Subject digest:
73f6e3336cf897944d868b60b099c092abcb8e92d37b13d016c59c13a7822266 - Sigstore transparency entry: 2160687266
- Sigstore integration time:
-
Permalink:
docling-project/docling.rs@98f5326c6019d3517aca086bb267de5c6bf22f25 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/docling-project
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@98f5326c6019d3517aca086bb267de5c6bf22f25 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file docling_rs-0.15.1-cp39-abi3-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: docling_rs-0.15.1-cp39-abi3-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 17.9 MB
- Tags: CPython 3.9+, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
74346e992c257e570ac310e9c01ba7b250621fcbadfb30753da24cea3341faed
|
|
| MD5 |
9c9e0e6a3bf609a0d21b88c4265a4be6
|
|
| BLAKE2b-256 |
2f15f299b52274fee59e69c5df9e5614818c46a4768fe04a7216770d582393f2
|
Provenance
The following attestation bundles were made for docling_rs-0.15.1-cp39-abi3-manylinux_2_28_aarch64.whl:
Publisher:
pypi-publish.yml on docling-project/docling.rs
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
docling_rs-0.15.1-cp39-abi3-manylinux_2_28_aarch64.whl -
Subject digest:
74346e992c257e570ac310e9c01ba7b250621fcbadfb30753da24cea3341faed - Sigstore transparency entry: 2160687112
- Sigstore integration time:
-
Permalink:
docling-project/docling.rs@98f5326c6019d3517aca086bb267de5c6bf22f25 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/docling-project
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@98f5326c6019d3517aca086bb267de5c6bf22f25 -
Trigger Event:
workflow_dispatch
-
Statement type: