Skip to main content

mag-parse

One parse() for every document. PDFs go to mag-pdf; everything else goes to mag-file-handler.

from mag_parse import parse

r = parse("invoice.pdf")                      # quality="fast" (default)
r = parse("report.pdf", quality="accurate")   # table structure
r = parse("deck.pptx")                        # quality does not apply
r = parse(pdf_bytes, filename="report.pdf")   # bytes work too

r.markdown        # always populated
r.text            # always populated
r.format          # "pdf" | "docx" | "xlsx" | "eml" | ...
r.engine          # which engine actually ran
r.ok, r.error, r.warnings

The facade itself has zero required dependencies. Both engines are extras, and that is not tidiness — see Install.

Routing

Decided by magic bytes, never the extension. A .docx renamed to .pdf does not reach the PDF engine, and a PDF with no extension does.

parse(file, quality=...)
        │
   sniff %PDF
        │
   ┌────┴─────┐
 PDF        not PDF
   │            │
mag-pdf   mag-file-handler
   │            │
   └────┬───────┘
        ▼
    one Result

quality is a PDF-only knob

What runs Install
"fast" (default) LiteParse behind an OCR gate; OCRs only pages that need it mag-parse[pdf]
"accurate" DocLayout-YOLO + TableFormer for real table structure mag-parse[tables]

For every other format quality is accepted and ignored, so a caller never has to branch on file type. Result.quality is "" there — the knob did not default, it does not exist.

"accurate" selects mag-pdf's profile="tables", leaving table_mode at its default. Those are two different fast/accurate axes: the profile picks the pipeline, table_mode picks TableFormer's weights. The heavier weights measured 27.6 s against 16.1 s for one additional table row, so they are not what "accurate" buys — the table pipeline is.

Markdown, and how honest it is

Both .markdown and .text are always populated, on every path including failure. They are not equally structured, and structured_markdown says which you got:

Source .markdown structured
PDF real GFM — pipe tables, headings True
docx / xlsx / pptx / html / eml real GFM — headings and pipe tables True
md / txt / csv the text, which is already faithful False

Measured on generated fixtures with known content: every format above recovers 100% of its title, prose, table cells and numeric values, and seven of the eight produce pipe tables a chunker can find. Plain text is the exception, and correctly so — there is no table in it to preserve.

Read result.structured, not the raw structured_markdown field. The property additionally requires that an extraction succeeded and that the markdown really does contain a heading or a table; the raw field is set by the engine adapter and reported True even for an error result carrying no markdown at all.

Errors

A bad document is a Result, never an exception — check .ok / .error. Only two things raise, and both are the caller's to fix:

Exception Means
UnknownQuality quality= was not "fast" or "accurate". Raised before any I/O, so a typo cannot run the wrong pipeline on a large file first.
EngineNotAvailable The extra for this file type is not installed. Names the exact pip install.

Result.status is "ok", "empty" or "error". empty is a failure — an extraction that returns nothing while reporting success is the silent failure both engines guard against, and the facade does not launder it.

HTTP server

pip install 'mag-parse[http,pdf,office]'
mag-parse-http --host 0.0.0.0 --port 8080
curl -sf -F file=@invoice.pdf -F quality=accurate localhost:8080/v1/parse
curl -sf -F file=@notes.docx localhost:8080/v1/parse -H 'Accept: text/markdown'
curl -s localhost:8080/readyz
Endpoint What it is for
POST /v1/parse multipart: file, quality=fast|accurate, password?
GET /livez process alive - restart only if this fails
GET /readyz engines warm - stop routing if this fails
GET /metrics Prometheus
GET /version version, lanes, active limits

A bad document is 200 with ok: false; a bad server is 4xx/5xx as application/problem+json. X-Request-Id is echoed if you send one, minted if you do not.

Set MAGPARSE_FAIL_ON_EMPTY=true to turn an extraction that produced no content into a 422 rather than a 200 nobody notices.

Install

pip install 'mag-parse[pdf]'        # PDFs; one dependency, Tesseract bundled
pip install 'mag-parse[office]'     # docx, xlsx, pptx, eml, html, md, txt, csv
pip install 'mag-parse[all]'        # both of the above
pip install 'mag-parse[tables]'     # adds quality="accurate" (~2 GB: torch)
pip install 'mag-parse[all,http]'   # + the HTTP server (`mag-parse-http`)

serve carries no engine on purpose - it is composed with whichever of the above you need, so a PDF-only sidecar does not inherit the office stack's platform limits.

The engines are extras rather than dependencies because extractous (under mag-file-handler) publishes no Linux ARM64 wheel and declares requires-python <3.14, while liteparse (under mag-pdf) has neither limit. Making the office side required would impose both constraints on PDF-only users:

Platform [pdf] [office]
Linux x86-64 ✅ ✅
Linux ARM64 ✅ ❌ no wheel
macOS ARM64 / x86-64 ✅ ✅
Windows x86-64 ✅ ✅
Python 3.14 ✅ ❌ <3.14

Python 3.10+. Apache-2.0.

Metadata

Release files for mag-parse 0.3.1

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

Source distribution (sdist)

Source distribution for mag-parse 0.3.1
File Size Uploaded
mag_parse-0.3.1.tar.gz 44.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mag-parse 0.3.1
File Interpreter ABI Platform
mag_parse-0.3.1-py3-none-any.whl Python 3 none any Details

Total release size: 80.5 kB

Release files / mag_parse-0.3.1.tar.gz

Download URL mag_parse-0.3.1.tar.gz
Size 44.6 kB
Tags Source
SHA-256 checksum
How to use checksums
9e5850a31f05aa3f31043fd8ceece37b0272b0bbb82256393c7fad085dbd8629
BLAKE2b-256 checksum
How to use checksums
2dddcd0119c04cd2bfadb1e9696ba3a782cfd51caa7e970f0853c9be6ab2f35f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

Release files / mag_parse-0.3.1-py3-none-any.whl

Download URL mag_parse-0.3.1-py3-none-any.whl
Size 35.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
50982569021d7914f91fcfb41cddce4210652a4319082cb14f6ca2e17906fdef
BLAKE2b-256 checksum
How to use checksums
42cc2c30be86a70067ec50decd63192725e7dd72cc9a001a9622d33620654b45
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.1 This release

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release 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