Skip to main content

docspine

PyPI

A pure-Rust Word (.docx) parser with Python bindings (PyO3 / maturin, abi3-py311). A .docx file is OOXML — a zip archive of XML parts — and docspine walks word/document.xml directly to produce a structured, information-preserving model: paragraphs (styled runs), tables (rows, cells, merges, fills, nesting), and embedded pictures. Tables are a first-class focus. Embedded images can additionally be OCR'd locally, offline, and deterministically via the sibling ocrspine crate (PP-OCRv5 through tract-onnx — no cloud, no network), and an image that is a table can be reconstructed into a grid from its OCR word boxes. A parsed document can also be exported to PDF (to_pdf() / save_pdf()) with flowed layout and pagination through the shared pure-Rust pdf-typeset engine from pdfspine — no LibreOffice, no cloud converter.

docspine is the document-engine sibling of pdfspine (PDF) and pptspine (PowerPoint), all sharing the same ocrspine OCR core.

Capabilities

Area Status
Body blocks: paragraphs + tables in document order parsed
Paragraphs: runs, text, style name, alignment, list level parsed
Run styling: font, size, bold, italic, underline, color parsed
Tables: rows, cells, cell paragraphs parsed
Table merges: gridSpan (horizontal) parsed
Table merges: vMerge restart / continue (vertical) parsed
Nested tables (a table inside a cell) parsed
Cell shading/fill, cell width (dxa), table grid columns parsed
Row height, header rows parsed
Embedded pictures: r:embed rel → media name + raw bytes + EMU extent parsed
Image OCR (embedded pictures → words + boxes) working (ocr_image)
Image-table reconstruction from OCR boxes → grid working (reconstruct_image_table)
PDF export: to_pdf() / save_pdf() — flowed layout + pagination; per-section page geometry (sectPr), styles.xml + theme effective styles, numbering engine, table fidelity (borders/merges/margins, cross-page; cell vAlign top/center/bottom), paragraph borders/shading, inline images + absolutely-positioned anchored images (no text wrap), hyperlinks as PDF link annotations, defaultTabStop tab advance working
Legacy binary .doc (OLE/CFB) probe + typed downgrade (full body deferred)

Parsing is tolerant: unknown elements are skipped, missing attributes become None, and malformed input yields a typed DocError rather than a panic.

docx first; legacy .doc deferred

Modern .docx (OOXML) is the primary target. The old binary .doc is a Microsoft compound document (OLE/CFB): rebuilding its body from the binary FIB + piece table is large, fiddly, and shares almost nothing with the docx path. So docspine ships detection + a clean typed downgrade today (a .doc byte stream yields DocUnsupportedError, and probe_doc reports the CFB streams when built with the legacy-doc feature); full .doc body reconstruction is a follow-up, not a blocker.

Install

pip install docspine

docspine is on PyPI. OCR works out of the box: the PP-OCRv5 weights ship in the shared ocrspine-models data package — a runtime dependency pip pulls in automatically — so a plain pip install docspine finds the OCR models with no extra setup (it no longer needs a sibling ../ocrspine/models checkout or OCRSPINE_MODELS). To build from source instead, see below.

Build (from the package root)

uv venv .venv
VIRTUAL_ENV="$(pwd)/.venv" uv pip install maturin pytest
# Structural parsing needs no models. The OCR path resolves models from a
# sibling ../ocrspine/models by default (or set OCRSPINE_MODELS).
OCRSPINE_MODELS="$(cd ../ocrspine && pwd)/models" \
  VIRTUAL_ENV="$(pwd)/.venv" .venv/bin/maturin develop --release

Use from Python

import docspine

doc = docspine.open("report.docx")
print(doc.block_count)

for block in doc.body():            # list[dict], introspectable
    if block["kind"] == "paragraph":
        for run in block["runs"]:
            print(run["text"], run["bold"], run["color"])
    elif block["kind"] == "table":
        for row in block["rows"]:
            for cell in row["cells"]:
                print(cell["text"], "span", cell["grid_span"], cell["v_merge"])

# Run OCR on raw image bytes (PNG/JPEG), offline:
items = docspine.ocr_image(open("scan.png", "rb").read())
print(" ".join(i["text"] for i in items))

# Reconstruct a table that lives inside an image into a grid:
for table in docspine.reconstruct_image_table(open("table.png", "rb").read()):
    for cell in table["cells"]:
        print(cell["row"], cell["col"], cell["text"])

Export to PDF

doc = docspine.open("report.docx")
doc.save_pdf("report.pdf")         # flowed layout + pagination
pdf_bytes = doc.to_pdf()           # or in-memory bytes

# Optional: map a requested font family to a local font file (or to another
# installed family), layered on top of the built-in substitution table:
doc.save_pdf("report.pdf", font_map={"Calibri": "/path/to/Carlito.ttf"})

Per-section page geometry from sectPr is honored (paper size, orientation, margins per section). Rendering is deterministic and fully offline. Missing fonts degrade gracefully: an available face is substituted and a Python UserWarning is emitted once per warning kind — the export never fails on a missing font.

Rust workspace

crates/
  doc-core    domain model + geometry (twip/EMU) + typed DocError. No IO/zip/XML.
  doc-parse   OOXML reader: zip extract + quick-xml walk -> Document.
              Legacy binary .doc probing behind the `legacy-doc` feature.
  doc-ocr     image-OCR bridge over ocrspine (PaddleOcr) + image-table reconstruction.
  doc-render  docx -> PDF renderer over the shared pdf-typeset engine (from pdfspine).
  py-bindings PyO3 _core extension (the FFI chokepoint); `ocr` feature gates OCR.

Deferred / follow-up

  • Full legacy binary .doc (OLE/CFB / [MS-DOC]) body reconstruction (FIB, piece table, CHPX/PAPX). Today: detection + typed downgrade + probe_doc.
  • Richer styling, headers/footers, footnotes/endnotes, comments, fields, hyperlinks targets, SmartArt/charts.

Download files

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

Source Distribution

docspine-0.5.1.tar.gz (158.7 kB view details)

Uploaded Source

Built Distributions

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

docspine-0.5.1-cp311-abi3-win_amd64.whl (10.4 MB view details)

Uploaded CPython 3.11+Windows x86-64

docspine-0.5.1-cp311-abi3-manylinux_2_28_aarch64.whl (9.5 MB view details)

Uploaded CPython 3.11+manylinux: glibc 2.28+ ARM64

docspine-0.5.1-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (10.5 MB view details)

Uploaded CPython 3.11+manylinux: glibc 2.17+ x86-64

docspine-0.5.1-cp311-abi3-macosx_11_0_arm64.whl (9.2 MB view details)

Uploaded CPython 3.11+macOS 11.0+ ARM64

docspine-0.5.1-cp311-abi3-macosx_10_12_x86_64.whl (10.1 MB view details)

Uploaded CPython 3.11+macOS 10.12+ x86-64

File details

Details for the file docspine-0.5.1.tar.gz.

File metadata

  • Download URL: docspine-0.5.1.tar.gz
  • Upload date:
  • Size: 158.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for docspine-0.5.1.tar.gz
Algorithm Hash digest
SHA256 e87ac09949341e363213000f0e420def9278142b9f3088a0cd833d39131734c4
MD5 ba6d0f30f0de9eb56edf500b1e8c172c
BLAKE2b-256 79e90c5a57167ee919b14be6a1a8206f25e5e17b339253201757073d2c33566a

See more details on using hashes here.

File details

Details for the file docspine-0.5.1-cp311-abi3-win_amd64.whl.

File metadata

  • Download URL: docspine-0.5.1-cp311-abi3-win_amd64.whl
  • Upload date:
  • Size: 10.4 MB
  • Tags: CPython 3.11+, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for docspine-0.5.1-cp311-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 7d57465b866ab755ee7ddce166ae01d1c852d71b8ce74d53f928e1267a265d3d
MD5 e6152f8983b591c04bee49a9bc7aa72e
BLAKE2b-256 c582a0eb0b1a8541ca2096f13552af0823ff21cce066776d620710b5076c1725

See more details on using hashes here.

File details

Details for the file docspine-0.5.1-cp311-abi3-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for docspine-0.5.1-cp311-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 e8dc0f7843a0058306d65596dce5b688f0c0120684d6e88a1ed5856559f7eb12
MD5 a7312cc857ab09a587c0b6a7ceaf7fa7
BLAKE2b-256 294bba593e3904c97ce2211a75f980078dce740bf8b209e5a39d589767d3f6b7

See more details on using hashes here.

File details

Details for the file docspine-0.5.1-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for docspine-0.5.1-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 24aeed45ddfbc9d04e74f00d690172b0f214a0b89cdf937da7e4d9c8b62a07cc
MD5 c7701d4e8d9f5092c9ec1b62c2c7bf81
BLAKE2b-256 7bc684ae4af67f443dcbb605ffe18a5e63af7b29ba78245c180866fd478667de

See more details on using hashes here.

File details

Details for the file docspine-0.5.1-cp311-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for docspine-0.5.1-cp311-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 3c0368f752402e96cce168afa86a279c78fde7bf13ca7ebdb3dfe8de9b10c9b4
MD5 fb983a6ada1c417382ff95b6cbde1fdc
BLAKE2b-256 59ce3b0c964ab0ea73f2cae8845d051ad1d3c769f108aefa86a470b9818b8ebd

See more details on using hashes here.

File details

Details for the file docspine-0.5.1-cp311-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for docspine-0.5.1-cp311-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 a7bd0c7f046464c6065635aa2f0cf995210b1861fdfb37d67847e869f33256e8
MD5 64ba80e859b37c46dfd60180605bc7df
BLAKE2b-256 21aea2932b12cc0350048c8af3590a53cf5524972ca879b4c172e404a619bc28

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.5.1 This release

6 files

0.5.0

6 files

0.4.0

6 files

0.3.0

6 files

0.2.0

6 files

0.1.1

6 files

0.1.0

5 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page