Metadata-Version: 2.4
Name: mag-parse
Version: 0.1.0
Summary: One parse() for every document - PDFs via mag-pdf, everything else via mag-file-handler
Author-email: Magure <aman.p@magureinc.com>
Maintainer-email: Magure <aman.p@magureinc.com>
License: Apache-2.0
Project-URL: Homepage, https://github.com/magurelabs/magoneai-file-handler
Project-URL: Source, https://github.com/magurelabs/magoneai-file-handler
Project-URL: Issues, https://github.com/magurelabs/magoneai-file-handler/issues
Keywords: pdf,docx,xlsx,ocr,extraction,markdown,parsing
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Text Processing
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Provides-Extra: pdf
Requires-Dist: mag-pdf<1,>=0.3; extra == "pdf"
Provides-Extra: tables
Requires-Dist: mag-pdf[tables]<1,>=0.3; extra == "tables"
Provides-Extra: office
Requires-Dist: mag-file-handler<1,>=0.3; extra == "office"
Provides-Extra: all
Requires-Dist: mag-parse[office,pdf]; extra == "all"
Provides-Extra: everything
Requires-Dist: mag-parse[office,tables]; extra == "everything"
Provides-Extra: test
Requires-Dist: pytest>=7; extra == "test"

# mag-parse

One `parse()` for every document. PDFs go to [`mag-pdf`](../magpdf);
everything else goes to [`mag-file-handler`](../file_handler).

```python
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](#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_markdown` |
|---|---|---|
| PDF | real GFM — pipe tables, headings | `True` |
| md / txt / csv | the text, which is already faithful | `False` |
| docx / xlsx / pptx / html / eml | the text, tables flattened | `False` + a warning |

A docx table currently arrives as tab-separated fragments rather than a pipe
table. That is `mag-file-handler`'s plain-text output passed through verbatim,
and the warning says so rather than letting it pass as structured markdown.
Teaching the engines real markdown per format is the planned follow-up; the
API does not change when it lands.

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

## Install

```bash
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)
```

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.
