Skip to main content

Pure-Rust Word (.docx / OOXML) structural parser with strong table support and local image OCR, via PyO3.

Project description

docspine

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.

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)
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.

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"])

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.
  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.
  • Bundling the PP-OCRv5 ONNX weights into the published wheel (a CI task).
  • Richer styling (theme colors, styles.xml inheritance), headers/footers, footnotes/endnotes, comments, fields, hyperlinks targets, SmartArt/charts.

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

docspine-0.1.0.tar.gz (54.0 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.1.0-cp311-abi3-win_amd64.whl (6.1 MB view details)

Uploaded CPython 3.11+Windows x86-64

docspine-0.1.0-cp311-abi3-manylinux_2_28_aarch64.whl (5.2 MB view details)

Uploaded CPython 3.11+manylinux: glibc 2.28+ ARM64

docspine-0.1.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (6.1 MB view details)

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

docspine-0.1.0-cp311-abi3-macosx_11_0_arm64.whl (4.9 MB view details)

Uploaded CPython 3.11+macOS 11.0+ ARM64

File details

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

File metadata

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

File hashes

Hashes for docspine-0.1.0.tar.gz
Algorithm Hash digest
SHA256 c55cff7deaee996ff4f9fb1f6db8fe3b9571eaa41e5581c9b015ca82fc45106d
MD5 5e60fc35164b23903a726df2f3e60da5
BLAKE2b-256 a1e63333dd38f22cdbc9ba080c7e7d998a971aec6d9ba9d1a21d43f5205c872b

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for docspine-0.1.0-cp311-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 6890b6f1645d196f336d44f841cee134a8828cffa4c1aaaafd7d016252d076b7
MD5 1d5b3d15cd71b8be5de0c41f0e529791
BLAKE2b-256 b33b6df8fdfac569c4835b4e1c21464546a4c650d7ff982884583df45b3a55b6

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for docspine-0.1.0-cp311-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 09d4c76bbc811f11c581cf9a7287a7151f6443fa717b16db7356a097f42c90b8
MD5 fa3530ef3c24431079dfff7c12d28235
BLAKE2b-256 a56bb51fc8abd88697ec1ff8d224803388edd69bba16097482997dcb0148eb1d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for docspine-0.1.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 b9cf2f00e2921d3cae46735469707a964b0e97483dcad936ab5761ff715e0922
MD5 05420a144b08a5a22ff6406e608eaf85
BLAKE2b-256 16b031bf775ced0b179c8e8d1325d5a5780c0b9a7665eb54e1f15bf56f8ccb9e

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for docspine-0.1.0-cp311-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 3f2b71e68f22ea7b1e200f1121fd54e8335d664c5c03cfc10033e79b31d0dde2
MD5 57d08ae1870c8dbc76260a1bda47993e
BLAKE2b-256 ca0addf09dcbb060ccbbf0bbd96fa3d396a90cbca4130c2da8f80943a30d66b3

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