fastdocparse 0.1.1__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. fastdocparse-0.3.0/PKG-INFO +163 -0
  2. fastdocparse-0.3.0/README.md +130 -0
  3. fastdocparse-0.3.0/pyproject.toml +66 -0
  4. {fastdocparse-0.1.1/src/docextract → fastdocparse-0.3.0/src/fastdocparse}/__init__.py +33 -21
  5. {fastdocparse-0.1.1/src/docextract → fastdocparse-0.3.0/src/fastdocparse}/cache.py +8 -7
  6. fastdocparse-0.3.0/src/fastdocparse/cli.py +232 -0
  7. {fastdocparse-0.1.1/src/docextract → fastdocparse-0.3.0/src/fastdocparse}/grounding.py +23 -25
  8. {fastdocparse-0.1.1/src/docextract → fastdocparse-0.3.0/src/fastdocparse}/json_repair.py +11 -7
  9. {fastdocparse-0.1.1/src/docextract → fastdocparse-0.3.0/src/fastdocparse}/llm_client.py +5 -4
  10. {fastdocparse-0.1.1/src/docextract → fastdocparse-0.3.0/src/fastdocparse}/ocr_engine.py +12 -8
  11. {fastdocparse-0.1.1/src/docextract → fastdocparse-0.3.0/src/fastdocparse}/parser.py +40 -28
  12. {fastdocparse-0.1.1/src/docextract → fastdocparse-0.3.0/src/fastdocparse}/pdf_utils.py +29 -20
  13. {fastdocparse-0.1.1/src/docextract → fastdocparse-0.3.0/src/fastdocparse}/prompt_compiler.py +6 -4
  14. fastdocparse-0.3.0/src/fastdocparse/result.py +75 -0
  15. {fastdocparse-0.1.1/src/docextract → fastdocparse-0.3.0/src/fastdocparse}/schema.py +14 -12
  16. {fastdocparse-0.1.1/src/docextract → fastdocparse-0.3.0/src/fastdocparse}/schema_compiler.py +2 -2
  17. fastdocparse-0.3.0/src/fastdocparse.egg-info/PKG-INFO +163 -0
  18. fastdocparse-0.3.0/src/fastdocparse.egg-info/SOURCES.txt +33 -0
  19. fastdocparse-0.3.0/src/fastdocparse.egg-info/entry_points.txt +2 -0
  20. fastdocparse-0.3.0/src/fastdocparse.egg-info/top_level.txt +1 -0
  21. {fastdocparse-0.1.1 → fastdocparse-0.3.0}/tests/test_architecture.py +22 -17
  22. fastdocparse-0.3.0/tests/test_cli.py +241 -0
  23. {fastdocparse-0.1.1 → fastdocparse-0.3.0}/tests/test_grounding.py +2 -2
  24. {fastdocparse-0.1.1 → fastdocparse-0.3.0}/tests/test_parser.py +33 -33
  25. {fastdocparse-0.1.1 → fastdocparse-0.3.0}/tests/test_schema_compiler.py +4 -3
  26. {fastdocparse-0.1.1 → fastdocparse-0.3.0}/tests/test_severe_edge_cases.py +71 -11
  27. fastdocparse-0.1.1/PKG-INFO +0 -138
  28. fastdocparse-0.1.1/README.md +0 -119
  29. fastdocparse-0.1.1/pyproject.toml +0 -35
  30. fastdocparse-0.1.1/src/docextract/cli.py +0 -140
  31. fastdocparse-0.1.1/src/docextract/result.py +0 -42
  32. fastdocparse-0.1.1/src/fastdocparse.egg-info/PKG-INFO +0 -138
  33. fastdocparse-0.1.1/src/fastdocparse.egg-info/SOURCES.txt +0 -33
  34. fastdocparse-0.1.1/src/fastdocparse.egg-info/entry_points.txt +0 -2
  35. fastdocparse-0.1.1/src/fastdocparse.egg-info/top_level.txt +0 -1
  36. fastdocparse-0.1.1/tests/test_cli.py +0 -129
  37. {fastdocparse-0.1.1 → fastdocparse-0.3.0}/LICENSE +0 -0
  38. {fastdocparse-0.1.1 → fastdocparse-0.3.0}/setup.cfg +0 -0
  39. {fastdocparse-0.1.1/src/docextract → fastdocparse-0.3.0/src/fastdocparse}/config.py +0 -0
  40. {fastdocparse-0.1.1/src/docextract → fastdocparse-0.3.0/src/fastdocparse}/example_schemas.py +0 -0
  41. {fastdocparse-0.1.1/src/docextract → fastdocparse-0.3.0/src/fastdocparse}/py.typed +0 -0
  42. {fastdocparse-0.1.1/src/docextract → fastdocparse-0.3.0/src/fastdocparse}/schemas/invoice.json +0 -0
  43. {fastdocparse-0.1.1/src/docextract → fastdocparse-0.3.0/src/fastdocparse}/schemas/shipment_manifest.json +0 -0
  44. {fastdocparse-0.1.1 → fastdocparse-0.3.0}/src/fastdocparse.egg-info/dependency_links.txt +0 -0
  45. {fastdocparse-0.1.1 → fastdocparse-0.3.0}/src/fastdocparse.egg-info/requires.txt +0 -0
@@ -0,0 +1,163 @@
1
+ Metadata-Version: 2.4
2
+ Name: fastdocparse
3
+ Version: 0.3.0
4
+ Summary: Extract structured data from semi-structured documents using any OpenAI-compatible LLM, with per-field grounding and confidence.
5
+ License-Expression: MIT
6
+ Project-URL: Homepage, https://github.com/pranjalparmar/fastdocparse
7
+ Project-URL: Repository, https://github.com/pranjalparmar/fastdocparse
8
+ Project-URL: Issues, https://github.com/pranjalparmar/fastdocparse/issues
9
+ Project-URL: Documentation, https://github.com/pranjalparmar/fastdocparse/tree/main/docs
10
+ Keywords: document-extraction,llm,pdf,ocr,invoice-extraction,structured-data,openai,ollama,grounding
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Intended Audience :: Developers
18
+ Classifier: Topic :: Text Processing :: Linguistic
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Requires-Python: <3.13,>=3.9
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: pydantic>=2.0
24
+ Requires-Dist: openai>=1.0
25
+ Requires-Dist: pymupdf>=1.24
26
+ Requires-Dist: pillow>=10.0
27
+ Requires-Dist: rapidocr-onnxruntime>=1.3
28
+ Requires-Dist: typer>=0.12
29
+ Requires-Dist: PyYAML>=6.0
30
+ Provides-Extra: dev
31
+ Requires-Dist: pytest; extra == "dev"
32
+ Dynamic: license-file
33
+
34
+ # fastdocparse
35
+
36
+ [![PyPI](https://img.shields.io/pypi/v/fastdocparse.svg)](https://pypi.org/project/fastdocparse/)
37
+ [![CI](https://github.com/pranjalparmar/fastdocparse/actions/workflows/ci.yml/badge.svg)](https://github.com/pranjalparmar/fastdocparse/actions/workflows/ci.yml)
38
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
39
+
40
+ Extract structured data from semi-structured documents (invoices, bills, tax forms, resumes, bank statements, shipment manifests) using any OpenAI-compatible LLM (OpenAI, Ollama, vLLM, Groq, etc.), with **per-field grounding and confidence**, not just raw extraction.
41
+
42
+ ## Why this, not just another parser
43
+
44
+ Most extractors give you a value and no way to know if it's real. This one tells you:
45
+
46
+ - **`grounded`**: the value was found verbatim (or near-verbatim) in the source document text.
47
+ - **`ungrounded`**: the value doesn't appear in the source, likely a hallucination. Flag for human review.
48
+ - **`missing_required`**: a field you marked required came back empty.
49
+ - **`invalid_format`**: the value doesn't match a pattern/enum constraint you declared (e.g. a shipment status outside the allowed list).
50
+ - **`failed_check`**: a custom cross-field rule failed (e.g. line items don't sum to the stated total).
51
+
52
+ No extra LLM call for any of this: it's deterministic, string/rule-based validation against text you already extracted.
53
+
54
+ **Where it fits:** semi-structured documents with recurring fields (invoices, bills, tax forms, resumes, statements), and prose documents where *proving* a value came from the source matters (contracts, legal clauses, insurance claims). It is not a vision-LLM pipeline. It works from extracted text (digital PDF text layer, or local OCR for scans/images), which is what keeps it fast, cheap, and usable with small local models. Messy handwritten forms or complex multi-column layouts are a known weaker spot (see [document-extractor-spec.md](document-extractor-spec.md)).
55
+
56
+ ## How this compares
57
+
58
+ | Project | Approach | Where it beats fastdocparse | Where fastdocparse can beat it |
59
+ |---|---|---|---|
60
+ | **[Sparrow](https://github.com/katanaml/sparrow)** (katanaml) | Vision-LLM first (MLX/vLLM/Ollama/Mistral OCR), multi-service platform, API-first | Layout-aware (sees the page), mature, table templates for complex tables | No GPU required, single `pip install`, Pydantic-schema devex vs. raw JSON-string CLI args |
61
+ | **[LangExtract](https://github.com/google/langextract)** (Google) | Text-first, source-grounding (character-offset mapping), few-shot examples required | Real grounding/traceability, brand trust | Purpose-built for documents (OCR routing) vs. text-in/text-out |
62
+
63
+ **The honest edge:** *fast, cheap, local-model-friendly extraction for clean-to-moderate documents*, not "better than Sparrow at everything." This has not yet been validated with a real head-to-head benchmark ([tracking issue](https://github.com/pranjalparmar/fastdocparse/issues/19)). Treat it as a design goal, not a proven claim, until that lands.
64
+
65
+ ## Two ways to use it
66
+
67
+ | | Who it's for | How |
68
+ |---|---|---|
69
+ | **CLI** | No coding needed | `fastdocparse extract <file> <schema.json>` / `fastdocparse --version` |
70
+ | **Python API** | Building it into your own app | `DocumentParser(client).extract(document_bytes, schema)` |
71
+
72
+ Defining *what* to extract also has two paths: hand-write a JSON/YAML schema file, or describe it in plain English and let the LLM draft the schema for you.
73
+
74
+ ## Install
75
+
76
+ ```bash
77
+ pip install fastdocparse
78
+ ```
79
+
80
+ For local development instead:
81
+
82
+ ```bash
83
+ git clone https://github.com/pranjalparmar/fastdocparse
84
+ cd fastdocparse
85
+ python -m venv venv
86
+ source venv/bin/activate # Windows: venv\Scripts\activate
87
+ pip install -e ".[dev]"
88
+ ```
89
+
90
+ You also need access to an LLM. Either:
91
+ - An OpenAI API key (`export OPENAI_API_KEY=...` or pass `--api-key`), or
92
+ - A local model via [Ollama](https://ollama.com/): no API key, no cloud, documents never leave your machine.
93
+
94
+ ## Quickstart: CLI (no coding)
95
+
96
+ ```bash
97
+ # 1. Extract using one of the bundled example schemas
98
+ fastdocparse extract sample_invoice.png src/fastdocparse/schemas/invoice.json \
99
+ --model gpt-4o-mini --api-key sk-...
100
+
101
+ # Or with a local model via Ollama (no API key needed):
102
+ fastdocparse extract sample_invoice.png src/fastdocparse/schemas/invoice.json \
103
+ --model llama3.2 --base-url http://localhost:11434/v1 --api-key ollama
104
+ ```
105
+
106
+ Output is JSON, printed to stdout (or saved with `--output result.json`):
107
+
108
+ ```json
109
+ {
110
+ "_meta": { "truncated": false, "truncation_reason": null },
111
+ "invoice_number": { "value": "INV-9011", "confidence": "high", "flags": ["grounded"] },
112
+ "total_price": { "value": 100.0, "confidence": "high", "flags": ["grounded"] }
113
+ }
114
+ ```
115
+
116
+ Don't want to write JSON at all? Describe the fields in plain English instead:
117
+
118
+ ```bash
119
+ fastdocparse schema-from-text \
120
+ "I want the invoice number, total price, and vendor name. Invoice number and total are required." \
121
+ --output my_invoice_schema.json
122
+
123
+ # review my_invoice_schema.json, then:
124
+ fastdocparse extract my_invoice.pdf my_invoice_schema.json
125
+ ```
126
+
127
+ ## Quickstart: Python API
128
+
129
+ ```python
130
+ from fastdocparse import Schema, Field, LLMClient, DocumentParser
131
+
132
+ schema = Schema(
133
+ name="Invoice",
134
+ fields=[
135
+ Field(name="invoice_number", description="The invoice number", required=True),
136
+ Field(name="total_price", description="Total amount due", type="number", required=True),
137
+ ],
138
+ )
139
+
140
+ client = LLMClient(model="gpt-4o-mini", api_key="sk-...")
141
+ # or: LLMClient(base_url="http://localhost:11434/v1", api_key="ollama", model="llama3.2")
142
+
143
+ parser = DocumentParser(client=client)
144
+
145
+ with open("invoice.pdf", "rb") as f:
146
+ result = parser.extract(f.read(), schema)
147
+
148
+ print(result["invoice_number"]) # {'value': 'INV-9011', 'confidence': 'high', 'flags': ['grounded']}
149
+ ```
150
+
151
+ ## Full documentation
152
+
153
+ - [Getting Started](docs/getting-started.md): step-by-step install, CLI, and API walkthroughs
154
+ - [Schema Guide](docs/schema-guide.md): every field option (`type`, `required`, `pattern`, `enum`, `sub_fields`, few-shot `examples`), for JSON, YAML, and plain-English authoring
155
+ - [Output & Validation](docs/output-format.md): the full result shape, what each confidence flag means, and how to write custom cross-check rules
156
+ - [Architecture](docs/architecture.md): diagrams of the pipeline, the module dependency graph, and where to plug in a contribution
157
+ - [Project spec](document-extractor-spec.md): architecture, phased roadmap, honest competitive positioning
158
+
159
+ Want to contribute? Start with [docs/architecture.md](docs/architecture.md) for the map, then [CONTRIBUTING.md](CONTRIBUTING.md) for the process.
160
+
161
+ ## Status
162
+
163
+ Core extraction, grounding, chunking, both CLI/API paths, and real packaging are implemented and tested (75 tests, `pytest -v`). Published on PyPI as [`fastdocparse`](https://pypi.org/project/fastdocparse/). `pip install fastdocparse` installs a working `fastdocparse` command and a proper `fastdocparse.*` import namespace, verified end to end with a clean-virtualenv install straight from the real public index. Not yet done: a hosted API. See [document-extractor-spec.md](document-extractor-spec.md) for the roadmap.
@@ -0,0 +1,130 @@
1
+ # fastdocparse
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/fastdocparse.svg)](https://pypi.org/project/fastdocparse/)
4
+ [![CI](https://github.com/pranjalparmar/fastdocparse/actions/workflows/ci.yml/badge.svg)](https://github.com/pranjalparmar/fastdocparse/actions/workflows/ci.yml)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
+
7
+ Extract structured data from semi-structured documents (invoices, bills, tax forms, resumes, bank statements, shipment manifests) using any OpenAI-compatible LLM (OpenAI, Ollama, vLLM, Groq, etc.), with **per-field grounding and confidence**, not just raw extraction.
8
+
9
+ ## Why this, not just another parser
10
+
11
+ Most extractors give you a value and no way to know if it's real. This one tells you:
12
+
13
+ - **`grounded`**: the value was found verbatim (or near-verbatim) in the source document text.
14
+ - **`ungrounded`**: the value doesn't appear in the source, likely a hallucination. Flag for human review.
15
+ - **`missing_required`**: a field you marked required came back empty.
16
+ - **`invalid_format`**: the value doesn't match a pattern/enum constraint you declared (e.g. a shipment status outside the allowed list).
17
+ - **`failed_check`**: a custom cross-field rule failed (e.g. line items don't sum to the stated total).
18
+
19
+ No extra LLM call for any of this: it's deterministic, string/rule-based validation against text you already extracted.
20
+
21
+ **Where it fits:** semi-structured documents with recurring fields (invoices, bills, tax forms, resumes, statements), and prose documents where *proving* a value came from the source matters (contracts, legal clauses, insurance claims). It is not a vision-LLM pipeline. It works from extracted text (digital PDF text layer, or local OCR for scans/images), which is what keeps it fast, cheap, and usable with small local models. Messy handwritten forms or complex multi-column layouts are a known weaker spot (see [document-extractor-spec.md](document-extractor-spec.md)).
22
+
23
+ ## How this compares
24
+
25
+ | Project | Approach | Where it beats fastdocparse | Where fastdocparse can beat it |
26
+ |---|---|---|---|
27
+ | **[Sparrow](https://github.com/katanaml/sparrow)** (katanaml) | Vision-LLM first (MLX/vLLM/Ollama/Mistral OCR), multi-service platform, API-first | Layout-aware (sees the page), mature, table templates for complex tables | No GPU required, single `pip install`, Pydantic-schema devex vs. raw JSON-string CLI args |
28
+ | **[LangExtract](https://github.com/google/langextract)** (Google) | Text-first, source-grounding (character-offset mapping), few-shot examples required | Real grounding/traceability, brand trust | Purpose-built for documents (OCR routing) vs. text-in/text-out |
29
+
30
+ **The honest edge:** *fast, cheap, local-model-friendly extraction for clean-to-moderate documents*, not "better than Sparrow at everything." This has not yet been validated with a real head-to-head benchmark ([tracking issue](https://github.com/pranjalparmar/fastdocparse/issues/19)). Treat it as a design goal, not a proven claim, until that lands.
31
+
32
+ ## Two ways to use it
33
+
34
+ | | Who it's for | How |
35
+ |---|---|---|
36
+ | **CLI** | No coding needed | `fastdocparse extract <file> <schema.json>` / `fastdocparse --version` |
37
+ | **Python API** | Building it into your own app | `DocumentParser(client).extract(document_bytes, schema)` |
38
+
39
+ Defining *what* to extract also has two paths: hand-write a JSON/YAML schema file, or describe it in plain English and let the LLM draft the schema for you.
40
+
41
+ ## Install
42
+
43
+ ```bash
44
+ pip install fastdocparse
45
+ ```
46
+
47
+ For local development instead:
48
+
49
+ ```bash
50
+ git clone https://github.com/pranjalparmar/fastdocparse
51
+ cd fastdocparse
52
+ python -m venv venv
53
+ source venv/bin/activate # Windows: venv\Scripts\activate
54
+ pip install -e ".[dev]"
55
+ ```
56
+
57
+ You also need access to an LLM. Either:
58
+ - An OpenAI API key (`export OPENAI_API_KEY=...` or pass `--api-key`), or
59
+ - A local model via [Ollama](https://ollama.com/): no API key, no cloud, documents never leave your machine.
60
+
61
+ ## Quickstart: CLI (no coding)
62
+
63
+ ```bash
64
+ # 1. Extract using one of the bundled example schemas
65
+ fastdocparse extract sample_invoice.png src/fastdocparse/schemas/invoice.json \
66
+ --model gpt-4o-mini --api-key sk-...
67
+
68
+ # Or with a local model via Ollama (no API key needed):
69
+ fastdocparse extract sample_invoice.png src/fastdocparse/schemas/invoice.json \
70
+ --model llama3.2 --base-url http://localhost:11434/v1 --api-key ollama
71
+ ```
72
+
73
+ Output is JSON, printed to stdout (or saved with `--output result.json`):
74
+
75
+ ```json
76
+ {
77
+ "_meta": { "truncated": false, "truncation_reason": null },
78
+ "invoice_number": { "value": "INV-9011", "confidence": "high", "flags": ["grounded"] },
79
+ "total_price": { "value": 100.0, "confidence": "high", "flags": ["grounded"] }
80
+ }
81
+ ```
82
+
83
+ Don't want to write JSON at all? Describe the fields in plain English instead:
84
+
85
+ ```bash
86
+ fastdocparse schema-from-text \
87
+ "I want the invoice number, total price, and vendor name. Invoice number and total are required." \
88
+ --output my_invoice_schema.json
89
+
90
+ # review my_invoice_schema.json, then:
91
+ fastdocparse extract my_invoice.pdf my_invoice_schema.json
92
+ ```
93
+
94
+ ## Quickstart: Python API
95
+
96
+ ```python
97
+ from fastdocparse import Schema, Field, LLMClient, DocumentParser
98
+
99
+ schema = Schema(
100
+ name="Invoice",
101
+ fields=[
102
+ Field(name="invoice_number", description="The invoice number", required=True),
103
+ Field(name="total_price", description="Total amount due", type="number", required=True),
104
+ ],
105
+ )
106
+
107
+ client = LLMClient(model="gpt-4o-mini", api_key="sk-...")
108
+ # or: LLMClient(base_url="http://localhost:11434/v1", api_key="ollama", model="llama3.2")
109
+
110
+ parser = DocumentParser(client=client)
111
+
112
+ with open("invoice.pdf", "rb") as f:
113
+ result = parser.extract(f.read(), schema)
114
+
115
+ print(result["invoice_number"]) # {'value': 'INV-9011', 'confidence': 'high', 'flags': ['grounded']}
116
+ ```
117
+
118
+ ## Full documentation
119
+
120
+ - [Getting Started](docs/getting-started.md): step-by-step install, CLI, and API walkthroughs
121
+ - [Schema Guide](docs/schema-guide.md): every field option (`type`, `required`, `pattern`, `enum`, `sub_fields`, few-shot `examples`), for JSON, YAML, and plain-English authoring
122
+ - [Output & Validation](docs/output-format.md): the full result shape, what each confidence flag means, and how to write custom cross-check rules
123
+ - [Architecture](docs/architecture.md): diagrams of the pipeline, the module dependency graph, and where to plug in a contribution
124
+ - [Project spec](document-extractor-spec.md): architecture, phased roadmap, honest competitive positioning
125
+
126
+ Want to contribute? Start with [docs/architecture.md](docs/architecture.md) for the map, then [CONTRIBUTING.md](CONTRIBUTING.md) for the process.
127
+
128
+ ## Status
129
+
130
+ Core extraction, grounding, chunking, both CLI/API paths, and real packaging are implemented and tested (75 tests, `pytest -v`). Published on PyPI as [`fastdocparse`](https://pypi.org/project/fastdocparse/). `pip install fastdocparse` installs a working `fastdocparse` command and a proper `fastdocparse.*` import namespace, verified end to end with a clean-virtualenv install straight from the real public index. Not yet done: a hosted API. See [document-extractor-spec.md](document-extractor-spec.md) for the roadmap.
@@ -0,0 +1,66 @@
1
+ [project]
2
+ name = "fastdocparse"
3
+ version = "0.3.0"
4
+ description = "Extract structured data from semi-structured documents using any OpenAI-compatible LLM, with per-field grounding and confidence."
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ requires-python = ">=3.9,<3.13" # capped by rapidocr-onnxruntime's own upper bound (checked live against PyPI)
8
+ keywords = [
9
+ "document-extraction",
10
+ "llm",
11
+ "pdf",
12
+ "ocr",
13
+ "invoice-extraction",
14
+ "structured-data",
15
+ "openai",
16
+ "ollama",
17
+ "grounding",
18
+ ]
19
+ classifiers = [
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.9",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Operating System :: OS Independent",
26
+ "Intended Audience :: Developers",
27
+ "Topic :: Text Processing :: Linguistic",
28
+ "Topic :: Software Development :: Libraries :: Python Modules",
29
+ ]
30
+ dependencies = [
31
+ "pydantic>=2.0",
32
+ "openai>=1.0",
33
+ "pymupdf>=1.24",
34
+ "pillow>=10.0",
35
+ "rapidocr-onnxruntime>=1.3",
36
+ "typer>=0.12",
37
+ "PyYAML>=6.0",
38
+ ]
39
+
40
+ [project.optional-dependencies]
41
+ dev = ["pytest"]
42
+
43
+ [project.urls]
44
+ Homepage = "https://github.com/pranjalparmar/fastdocparse"
45
+ Repository = "https://github.com/pranjalparmar/fastdocparse"
46
+ Issues = "https://github.com/pranjalparmar/fastdocparse/issues"
47
+ Documentation = "https://github.com/pranjalparmar/fastdocparse/tree/main/docs"
48
+
49
+ [project.scripts]
50
+ fastdocparse = "fastdocparse.cli:app"
51
+
52
+ [build-system]
53
+ requires = ["setuptools>=68"]
54
+ build-backend = "setuptools.build_meta"
55
+
56
+ [tool.setuptools.packages.find]
57
+ where = ["src"]
58
+
59
+ [tool.setuptools.package-data]
60
+ fastdocparse = ["schemas/*.json", "py.typed"]
61
+
62
+ [tool.pytest.ini_options]
63
+ testpaths = ["tests"]
64
+
65
+ [tool.ruff.lint.per-file-ignores]
66
+ "src/fastdocparse/cli.py" = ["B008"]
@@ -1,7 +1,7 @@
1
- """docextract — extract structured data from semi-structured documents using any
1
+ """fastdocparse — extract structured data from semi-structured documents using any
2
2
  OpenAI-compatible LLM, with per-field grounding and confidence.
3
3
 
4
- from docextract import Schema, Field, LLMClient, DocumentParser
4
+ from fastdocparse import Schema, Field, LLMClient, DocumentParser
5
5
 
6
6
  schema = Schema(name="Invoice", fields=[Field(name="total", description="Grand total", type="number")])
7
7
  client = LLMClient(model="gpt-4o-mini", api_key="sk-...")
@@ -10,43 +10,55 @@ OpenAI-compatible LLM, with per-field grounding and confidence.
10
10
 
11
11
  from .cache import Cache, InMemoryCache
12
12
  from .config import ExtractionConfig
13
- from .grounding import Issue, check_substring, cross_check, date_parseable_rule, numeric_sum_rule, validate_field_constraints
13
+ from .grounding import (
14
+ Issue,
15
+ check_substring,
16
+ cross_check,
17
+ date_parseable_rule,
18
+ numeric_sum_rule,
19
+ validate_field_constraints,
20
+ )
14
21
  from .llm_client import LLMClient, LLMClientError
15
- from .parser import DocumentParser, EmptyDocumentError, UnknownIngestionKindError, register_default_ingestion_handler
22
+ from .parser import (
23
+ DocumentParser,
24
+ EmptyDocumentError,
25
+ UnknownIngestionKindError,
26
+ register_default_ingestion_handler,
27
+ )
16
28
  from .result import ExtractionMeta, ExtractionResult, FieldResult
17
29
  from .schema import Field, Schema
18
30
  from .schema_compiler import compile_schema_from_description
19
31
 
20
32
  try:
33
+ from importlib.metadata import PackageNotFoundError
21
34
  from importlib.metadata import version as _pkg_version
22
- # Looks up by the PyPI *distribution* name, not the import name — these differ
23
- # ("docextract" was blocked by PyPI's name-similarity rule against the existing
24
- # "doc-extract", so the distribution is registered as "fastdocparse"). Keep this
25
- # in sync with pyproject.toml's [project] name if that ever changes again.
35
+
36
+ # Looks up by the PyPI *distribution* name (pyproject.toml's [project] name) — keep
37
+ # this string in sync with that if the distribution is ever renamed again.
26
38
  __version__ = _pkg_version("fastdocparse")
27
- except Exception:
39
+ except PackageNotFoundError:
28
40
  __version__ = "0.0.0+unknown"
29
41
 
30
42
  __all__ = [
31
- "Schema",
32
- "Field",
33
- "LLMClient",
34
- "LLMClientError",
43
+ "Cache",
35
44
  "DocumentParser",
36
45
  "EmptyDocumentError",
37
- "UnknownIngestionKindError",
38
- "register_default_ingestion_handler",
39
46
  "ExtractionConfig",
40
- "Cache",
41
- "InMemoryCache",
47
+ "ExtractionMeta",
42
48
  "ExtractionResult",
49
+ "Field",
43
50
  "FieldResult",
44
- "ExtractionMeta",
51
+ "InMemoryCache",
45
52
  "Issue",
53
+ "LLMClient",
54
+ "LLMClientError",
55
+ "Schema",
56
+ "UnknownIngestionKindError",
46
57
  "check_substring",
58
+ "compile_schema_from_description",
47
59
  "cross_check",
48
- "validate_field_constraints",
49
- "numeric_sum_rule",
50
60
  "date_parseable_rule",
51
- "compile_schema_from_description",
61
+ "numeric_sum_rule",
62
+ "register_default_ingestion_handler",
63
+ "validate_field_constraints",
52
64
  ]
@@ -4,19 +4,20 @@ Caching is skipped whenever custom `rules` are passed to extract(), since a rule
4
4
  arbitrary callable that can't be safely fingerprinted — caching would risk returning a
5
5
  result validated under a different rule than the one just requested.
6
6
  """
7
+ from __future__ import annotations
7
8
 
8
9
  import hashlib
9
10
  import json
10
11
  from collections import OrderedDict
11
- from typing import Any, Callable, Dict, Optional, Protocol
12
+ from typing import Any, Callable, Protocol
12
13
 
13
14
  from .config import ExtractionConfig
14
15
  from .schema import Schema
15
16
 
16
17
 
17
18
  class Cache(Protocol):
18
- def get(self, key: str) -> Optional[Dict[str, Any]]: ...
19
- def set(self, key: str, value: Dict[str, Any]) -> None: ...
19
+ def get(self, key: str) -> dict[str, Any] | None: ...
20
+ def set(self, key: str, value: dict[str, Any]) -> None: ...
20
21
 
21
22
 
22
23
  class InMemoryCache:
@@ -27,19 +28,19 @@ class InMemoryCache:
27
28
  process exits before the cache could grow unbounded.
28
29
  """
29
30
 
30
- def __init__(self, max_size: Optional[int] = None):
31
+ def __init__(self, max_size: int | None = None):
31
32
  if max_size is not None and max_size <= 0:
32
33
  raise ValueError(f"max_size must be positive, got {max_size}")
33
34
  self._max_size = max_size
34
- self._store: "OrderedDict[str, Dict[str, Any]]" = OrderedDict()
35
+ self._store: OrderedDict[str, dict[str, Any]] = OrderedDict()
35
36
 
36
- def get(self, key: str) -> Optional[Dict[str, Any]]:
37
+ def get(self, key: str) -> dict[str, Any] | None:
37
38
  if key not in self._store:
38
39
  return None
39
40
  self._store.move_to_end(key)
40
41
  return self._store[key]
41
42
 
42
- def set(self, key: str, value: Dict[str, Any]) -> None:
43
+ def set(self, key: str, value: dict[str, Any]) -> None:
43
44
  self._store[key] = value
44
45
  self._store.move_to_end(key)
45
46
  if self._max_size is not None: