Skip to main content

undoc

High-performance Microsoft Office document extraction to Markdown.

Installation

pip install undoc

Usage

Basic Usage

from undoc import parse_file

# Parse a document
doc = parse_file("document.docx")

# Convert to Markdown
markdown = doc.to_markdown()
print(markdown)

# Convert to plain text
text = doc.to_text()

# Convert to JSON
json_data = doc.to_json()

With Context Manager

from undoc import parse_file

with parse_file("document.xlsx") as doc:
    print(doc.to_markdown(frontmatter=True))
    print(f"Sections: {doc.section_count}")
    print(f"Resources: {doc.resource_count}")

Parse from Bytes

from undoc import parse_bytes

with open("document.pptx", "rb") as f:
    data = f.read()

doc = parse_bytes(data)
markdown = doc.to_markdown()

Extract Resources (Images)

from undoc import parse_file

doc = parse_file("document.docx")

# Get all resource IDs
resource_ids = doc.get_resource_ids()

for rid in resource_ids:
    # Get resource metadata
    info = doc.get_resource_info(rid)
    # "primary": an image the document shows. "alternate" (a picture's SVG original) and
    # "layer" (an HD Photo effects layer) belong to the primary named by companion_of.
    if info["role"] != "primary":
        continue
    print(f"Resource: {info['filename']} ({info['mime_type']})")

    # Get resource binary data
    data = doc.get_resource_data(rid)

    # Save to file
    with open(info['filename'], 'wb') as f:
        f.write(data)

Document Metadata

from undoc import parse_file

doc = parse_file("document.docx")

print(f"Title: {doc.title}")
print(f"Author: {doc.author}")
print(f"Sections: {doc.section_count}")
print(f"Resources: {doc.resource_count}")

Render a Slide

A slide of a .pptx renders to PNG from the parsed document, without reading the file again:

from undoc import parse_file

with parse_file("deck.pptx") as doc:
    slide = doc.render_section(0, dpi=150)
    with open("slide1.png", "wb") as f:
        f.write(slide.png)
    if any(slide.gaps.values()):
        print("not painted:", slide.gaps)

What the renderer cannot paint yet — charts, embedded objects and other graphic frames, custom geometry, pictures other than PNG and JPEG, text in a script that needs shaping — is left out and counted in gaps; the rest of the slide is painted. No font is bundled. Text is drawn in the directories you name (font_dirs), then the system's. A Linux container without fonts draws no text — install a font package (Noto Sans CJK covers Latin and East Asian text) or pass a font directory — and reports the runs as gaps. A section the document does not have raises UndocError with kind == ErrorKind.SECTION_OUT_OF_RANGE; a document that is not a presentation, UNSUPPORTED_FORMAT.

Handling Failures

UndocError.kind says why a call failed, so you can react to the reason instead of matching on message text:

from undoc import ErrorKind, UndocError, parse_file

try:
    doc = parse_file(path)
    print(doc.to_markdown())
except UndocError as err:
    if err.kind is ErrorKind.ZIP_ARCHIVE:
        print("The file is damaged.")
    elif err.kind in (ErrorKind.UNKNOWN_FORMAT, ErrorKind.UNSUPPORTED_FORMAT):
        print("Not a supported Office document.")
    elif err.kind is ErrorKind.ENCRYPTED:
        print("The document is encrypted.")
    else:
        # Also the right branch for a reason this build has no name for.
        print(f"Extraction failed ({err.kind}): {err}")

The numbers behind ErrorKind are a stable ABI contract: a new reason takes the next free number and existing ones are never renumbered. Always keep a final else — an unrecognised value arrives as a plain int rather than an ErrorKind, so that a newer native library stays usable. kind is ErrorKind.OTHER for failures raised by the wrapper itself, and never ErrorKind.NONE (which means success).

Supported Formats

  • DOCX - Microsoft Word documents
  • XLSX - Microsoft Excel spreadsheets
  • PPTX - Microsoft PowerPoint presentations

Features

  • RAG-Ready Output: Structured Markdown optimized for RAG/LLM applications
  • High Performance: Native Rust implementation via FFI
  • Asset Extraction: Images and embedded resources
  • Metadata Preservation: Document properties, styles, formatting
  • Cross-Platform: Windows, Linux, macOS (Intel & ARM)

API Reference

Functions

  • parse_file(path) - Parse document from file path
  • parse_bytes(data) - Parse document from bytes
  • version() - Get library version

Undoc Class

Conversion Methods

  • to_markdown(frontmatter=False, escape_special=True, paragraph_spacing=True, refine=False, *, ...) - Convert to Markdown (escape_special=False writes text without escaping Markdown special characters). Keyword-only, all defaulting to the library's own values: image_path_prefix, include_images, table_fallback ("markdown", "html"), max_heading_level (1-6), preserve_line_breaks, include_empty_paragraphs, list_marker, cleanup (None, "minimal", "standard", "aggressive"), revision_handling ("accept_all", "reject_all", "show_markup"), strip_redundant_emphasis_in_headings, emit_page_breaks, include_headers_footers, callout_blockquote, section_markers ("none", "comment"). A value the library cannot honour raises UndocError with ErrorKind.INVALID_ARGUMENT.
  • to_text() - Convert to plain text
  • to_json(compact=False) - Convert to JSON
  • plain_text() - Get plain text (fast extraction)

Properties

  • title - Document title
  • author - Document author
  • section_count - Number of sections
  • resource_count - Number of resources

Tables

  • get_tables(tsv=False) - Every table as CSV (RFC 4180), or tab-separated with tsv=True, in reading order: {"section", "index", "text"} — the section (a sheet, a slide, a document section), the table's place among that section's tables (from 1), and the text. A table nested in a cell is a table of its own, right after the one that holds it. A merged cell's text is in its top-left position and the positions it covers are empty, so every record has the same number of fields: pandas.read_csv(io.StringIO(t["text"])) reads one.

Resource Methods

  • get_resource_ids() - List of resource IDs
  • get_resource_info(id) - Resource metadata
  • get_resource_data(id) - Resource binary data

Rendering

  • render_section(index, dpi=150, font_dirs=(), system_fonts=True) - A slide as PNG, its size, and what was not painted (RenderedSection)

Native library

The package ships the native library for your platform. To load another build of it — one you compiled from the Rust crate, say — set UNDOC_LIB_PATH to that file. A path that names no file is an error: importing raises OSError naming the path, rather than quietly loading the packaged library instead.

License

MIT License - see LICENSE for details.

Metadata

Release files for undoc 0.24.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for undoc 0.24.0
File Size Uploaded
undoc-0.24.0.tar.gz 9.5 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for undoc 0.24.0
File Interpreter ABI Platform
undoc-0.24.0-py3-none-any.whl Python 3 none any Details

Total release size: 19.1 MB

Release files / undoc-0.24.0.tar.gz

Download URL undoc-0.24.0.tar.gz
Size 9.5 MB
Tags Source
SHA-256 checksum
How to use checksums
3ff039879300beeb201ab79104edd5cdc912064ee2cb6e691282535cb184a9d5
BLAKE2b-256 checksum
How to use checksums
3c3bf1fd8c4e3a217d96118c9b8e424371b4f11eacc4a04badc5904bbbf75ec3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / undoc-0.24.0-py3-none-any.whl

Download URL undoc-0.24.0-py3-none-any.whl
Size 9.6 MB
Tags Python 3
SHA-256 checksum
How to use checksums
1ac8b3ea5817e0f7a5d27a84cae74f4b94a20bba63506f2b18bc1793d146325e
BLAKE2b-256 checksum
How to use checksums
c11a3ef11dd0f830c5ccca4c650a77512cba486879a438eda631679cc40b9362
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

0.27.0

2 release files

0.26.0

2 release files

0.25.0

2 release files

This release

0.24.0 This release

2 release files

0.23.0

2 release files

0.22.0

2 release files

0.21.0

2 release files

0.13.0

2 release files

0.12.0

2 release files

0.11.0

2 release files

0.9.0

2 release files

0.8.1

1 release file

0.8.0

1 release file

0.7.0

1 release file

0.6.0

1 release file

0.5.5

1 release file

0.5.4

1 release file

0.5.3

1 release file

0.5.2

1 release file

0.5.1

1 release file

0.5.0

1 release file

0.3.1

1 release file

0.3.0

1 release file

0.2.2

1 release file

0.2.1

1 release file

0.2.0

1 release file

0.1.20

1 release file

0.1.19

1 release file

0.1.18

1 release file

0.1.17

1 release file

0.1.16

1 release file

0.1.15

1 release file

0.1.13

1 release file

0.1.11

1 release file

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