DocmaxV3 3.0.0a7__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 (39) hide show
  1. docmaxv3-3.0.0a7/LICENSE +21 -0
  2. docmaxv3-3.0.0a7/PKG-INFO +196 -0
  3. docmaxv3-3.0.0a7/README.md +132 -0
  4. docmaxv3-3.0.0a7/pyproject.toml +240 -0
  5. docmaxv3-3.0.0a7/setup.cfg +4 -0
  6. docmaxv3-3.0.0a7/src/DocmaxV3.egg-info/PKG-INFO +196 -0
  7. docmaxv3-3.0.0a7/src/DocmaxV3.egg-info/SOURCES.txt +37 -0
  8. docmaxv3-3.0.0a7/src/DocmaxV3.egg-info/dependency_links.txt +1 -0
  9. docmaxv3-3.0.0a7/src/DocmaxV3.egg-info/entry_points.txt +2 -0
  10. docmaxv3-3.0.0a7/src/DocmaxV3.egg-info/requires.txt +43 -0
  11. docmaxv3-3.0.0a7/src/DocmaxV3.egg-info/top_level.txt +1 -0
  12. docmaxv3-3.0.0a7/src/docmax/__init__.py +23 -0
  13. docmaxv3-3.0.0a7/src/docmax/cli/__init__.py +8 -0
  14. docmaxv3-3.0.0a7/src/docmax/cli/main.py +99 -0
  15. docmaxv3-3.0.0a7/src/docmax/cli/render.py +58 -0
  16. docmaxv3-3.0.0a7/src/docmax/cloud_client/__init__.py +35 -0
  17. docmaxv3-3.0.0a7/src/docmax/cloud_client/client.py +343 -0
  18. docmaxv3-3.0.0a7/src/docmax/cloud_client/config.py +84 -0
  19. docmaxv3-3.0.0a7/src/docmax/cloud_client/errors.py +95 -0
  20. docmaxv3-3.0.0a7/src/docmax/cloud_client/models.py +189 -0
  21. docmaxv3-3.0.0a7/src/docmax/core/__init__.py +12 -0
  22. docmaxv3-3.0.0a7/src/docmax/core/atomic.py +282 -0
  23. docmaxv3-3.0.0a7/src/docmax/core/branding.py +53 -0
  24. docmaxv3-3.0.0a7/src/docmax/core/cancellation.py +235 -0
  25. docmaxv3-3.0.0a7/src/docmax/core/errors.py +472 -0
  26. docmaxv3-3.0.0a7/src/docmax/core/models.py +174 -0
  27. docmaxv3-3.0.0a7/src/docmax/core/protocols.py +107 -0
  28. docmaxv3-3.0.0a7/src/docmax/core/registry.py +248 -0
  29. docmaxv3-3.0.0a7/src/docmax/py.typed +0 -0
  30. docmaxv3-3.0.0a7/src/docmax/tools/__init__.py +15 -0
  31. docmaxv3-3.0.0a7/src/docmax/tools/merge/__init__.py +9 -0
  32. docmaxv3-3.0.0a7/src/docmax/tools/merge/local.py +80 -0
  33. docmaxv3-3.0.0a7/src/docmax/tools/merge/tool.py +35 -0
  34. docmaxv3-3.0.0a7/src/docmax/tools/merge/validators.py +63 -0
  35. docmaxv3-3.0.0a7/src/docmax/tools/ocr/__init__.py +10 -0
  36. docmaxv3-3.0.0a7/src/docmax/tools/ocr/cloud.py +78 -0
  37. docmaxv3-3.0.0a7/src/docmax/tools/ocr/local.py +96 -0
  38. docmaxv3-3.0.0a7/src/docmax/tools/ocr/tool.py +44 -0
  39. docmaxv3-3.0.0a7/src/docmax/tools/ocr/validators.py +37 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Punith Naidu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,196 @@
1
+ Metadata-Version: 2.4
2
+ Name: DocmaxV3
3
+ Version: 3.0.0a7
4
+ Summary: Terminal-native document toolkit. Local-first, dual-engine, no server required.
5
+ Author: Punith Naidu
6
+ Maintainer-email: Punith Naidu <punithmedaramitta@gmail.com>
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://github.com/megabyte44/docmax
9
+ Project-URL: Repository, https://github.com/megabyte44/docmax
10
+ Project-URL: Issues, https://github.com/megabyte44/docmax/issues
11
+ Project-URL: Changelog, https://github.com/megabyte44/docmax/blob/main/CHANGELOG.md
12
+ Keywords: pdf,ocr,document,cli,tui,terminal,conversion,batch
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: End Users/Desktop
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Office/Business
22
+ Classifier: Topic :: Utilities
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.11
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: typer>=0.12.0
28
+ Requires-Dist: rich>=13.7.0
29
+ Requires-Dist: pypdf>=4.2.0
30
+ Requires-Dist: platformdirs>=4.2.0
31
+ Requires-Dist: httpx>=0.27.0
32
+ Provides-Extra: ocr
33
+ Requires-Dist: pytesseract>=0.3.10; extra == "ocr"
34
+ Requires-Dist: pdf2image>=1.17.0; extra == "ocr"
35
+ Requires-Dist: opencv-python-headless>=4.9.0; extra == "ocr"
36
+ Requires-Dist: numpy>=1.26.0; extra == "ocr"
37
+ Provides-Extra: tables
38
+ Requires-Dist: pdfplumber>=0.11.0; extra == "tables"
39
+ Requires-Dist: pandas>=2.2.0; extra == "tables"
40
+ Requires-Dist: openpyxl>=3.1.0; extra == "tables"
41
+ Provides-Extra: images
42
+ Requires-Dist: Pillow>=10.3.0; extra == "images"
43
+ Requires-Dist: img2pdf>=0.5.0; extra == "images"
44
+ Provides-Extra: tui
45
+ Requires-Dist: textual>=0.60.0; extra == "tui"
46
+ Provides-Extra: server
47
+ Requires-Dist: DocmaxV3[all]; extra == "server"
48
+ Requires-Dist: fastapi>=0.111.0; extra == "server"
49
+ Requires-Dist: uvicorn[standard]>=0.30.0; extra == "server"
50
+ Requires-Dist: python-multipart>=0.0.9; extra == "server"
51
+ Provides-Extra: all
52
+ Requires-Dist: DocmaxV3[images,ocr,tables,tui]; extra == "all"
53
+ Provides-Extra: dev
54
+ Requires-Dist: pytest>=8.2.0; extra == "dev"
55
+ Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
56
+ Requires-Dist: pytest-timeout>=2.3.0; extra == "dev"
57
+ Requires-Dist: hypothesis>=6.100.0; extra == "dev"
58
+ Requires-Dist: respx>=0.21.0; extra == "dev"
59
+ Requires-Dist: ruff>=0.5.0; extra == "dev"
60
+ Requires-Dist: mypy>=1.10.0; extra == "dev"
61
+ Requires-Dist: import-linter>=2.0; extra == "dev"
62
+ Requires-Dist: pre-commit>=3.7.0; extra == "dev"
63
+ Dynamic: license-file
64
+
65
+ # DocMax
66
+
67
+ **A document toolkit that lives in your terminal.** Merge, split, OCR, compress,
68
+ convert, redact — locally, privately, with no server to run and no browser tab
69
+ to open.
70
+
71
+ ```bash
72
+ pip install DocmaxV3
73
+ docmax merge a.pdf b.pdf -o combined.pdf
74
+ ```
75
+
76
+ > **Status: early development (M0).** The architecture and safety mechanisms are
77
+ > in place; the tools are being rebuilt on top of them one at a time. For a
78
+ > working tool today, use [`docmax` 2.x](https://pypi.org/project/docmax/).
79
+ > See [the roadmap](#roadmap) for what lands when.
80
+
81
+ ---
82
+
83
+ ## Why another PDF tool
84
+
85
+ The good self-hosted options — Stirling PDF and friends — are excellent, and
86
+ they all assume a browser. That means Docker, a running server, a port, and no
87
+ sensible way to use them over SSH or from a script.
88
+
89
+ DocMax assumes a terminal instead.
90
+
91
+ | | DocMax | Self-hosted web tools |
92
+ |---|---|---|
93
+ | Install | `pip install DocmaxV3` | Docker + a container |
94
+ | Interface | CLI and TUI | browser |
95
+ | Over SSH | works | needs port forwarding |
96
+ | Scripting | argv | HTTP against a running server |
97
+ | Your documents | stay on your machine | stay on your machine |
98
+
99
+ ## Two engines, one interface
100
+
101
+ Every operation can run two ways, and the choice is yours per tool:
102
+
103
+ - **Local** — offline and private. Needs the relevant dependencies installed.
104
+ - **Cloud** — no local install at all. For the handful of tools whose
105
+ dependencies are genuinely painful.
106
+
107
+ ```bash
108
+ docmax ocr scan.pdf # picks whichever is available
109
+ docmax ocr scan.pdf --engine local # force local
110
+ docmax ocr scan.pdf --engine cloud # skip installing Tesseract
111
+ ```
112
+
113
+ Cloud exists for exactly one reason — to let you use a tool without installing
114
+ its heavy dependencies. Only five tools have it (`ocr`, `compress`, `convert`,
115
+ `pdfa`, `remove-bg`), because for a pure-Python operation like `merge`,
116
+ uploading your document would be slower, less private, and pointless.
117
+
118
+ **Nothing is ever uploaded without asking.** Consent is per-tool and remembered;
119
+ `offline = true` in your config disables cloud entirely regardless of flags; and
120
+ every upload tells you what it is sending before it sends it. The cloud endpoint
121
+ is configurable, so you can point DocMax at your own server instead.
122
+
123
+ ## Your files are safe
124
+
125
+ This is the part most tools get wrong, so it is worth being specific.
126
+
127
+ - **Atomic writes.** Output goes to a temp file, gets validated, and is only then
128
+ swapped into place. A crash or Ctrl-C mid-operation leaves your destination
129
+ either untouched or absent — never half-written.
130
+ - **Your input is never the output.** `docmax merge a.pdf b.pdf -o a.pdf` is
131
+ refused, not silently obeyed.
132
+ - **Nothing is overwritten by accident.** Existing files need `--force`.
133
+ - **No tracebacks.** Every anticipated failure gives you a plain message and the
134
+ next step to take.
135
+
136
+ These are enforced by tests that run on every commit across Linux, macOS, and
137
+ Windows — not by good intentions. See
138
+ [architecture.md](docs/architecture.md#the-structural-guarantees).
139
+
140
+ ## Install
141
+
142
+ ```bash
143
+ pip install DocmaxV3 # the shell and the cloud client
144
+ pip install "DocmaxV3[ocr]" # local OCR
145
+ pip install "DocmaxV3[all]" # everything
146
+ ```
147
+
148
+ The base install is deliberately small. Heavy dependencies arrive only when you
149
+ first ask for a local engine that needs them.
150
+
151
+ Some local engines also need external programs (Ghostscript, Tesseract, Pandoc,
152
+ Poppler):
153
+
154
+ ```bash
155
+ docmax doctor # what's installed, what's missing, what needs it
156
+ ```
157
+
158
+ ## Roadmap
159
+
160
+ | | | |
161
+ |---|---|---|
162
+ | **M0** | Foundation — architecture, CI, safety mechanisms | ✅ done |
163
+ | **M1** | Core engine + `merge` as the reference implementation | in progress |
164
+ | **M2** | `split`, `rotate`, `reorder`, `pages`, `metadata`, `sanitize`, `get-info` | |
165
+ | **M3** | `compress` + a real `setup` / `doctor` | |
166
+ | **M4** | `watermark`, `stamp`, `protect`, `unlock`, `permissions` | |
167
+ | **M5** | `convert`, `to-images`, `from-images` | |
168
+ | **M6** | Cloud engines, `--json` everywhere, published benchmarks | |
169
+ | **M7** | Textual TUI + visual pickers for crop and reorder | |
170
+ | **M8** | OCR, done properly | |
171
+ | **M9** | Pipelines, resumable batch, folder watch | |
172
+ | **M10** | Local MCP server — drive DocMax from an AI agent, nothing leaves your machine | |
173
+
174
+ Benchmarks will be published in `benchmarks/` with real hardware and
175
+ methodology. No numbers appear in this README until they are measured.
176
+
177
+ ## Contributing
178
+
179
+ ```bash
180
+ git clone https://github.com/megabyte44/docmax
181
+ cd docmax
182
+ python -m venv .venv && .venv/bin/pip install -e ".[dev]"
183
+ pre-commit install
184
+
185
+ pytest && ruff check . && mypy && lint-imports
186
+ ```
187
+
188
+ Start with [docs/architecture.md](docs/architecture.md) and the
189
+ [ADRs](docs/adr/) — they explain the constraints, most of which exist for a
190
+ specific reason.
191
+
192
+ ## Licence
193
+
194
+ MIT. Every document operation is free and always will be — see
195
+ [ADR 0004](docs/adr/0004-open-core-boundary.md) for where the open-core line
196
+ sits and why.
@@ -0,0 +1,132 @@
1
+ # DocMax
2
+
3
+ **A document toolkit that lives in your terminal.** Merge, split, OCR, compress,
4
+ convert, redact — locally, privately, with no server to run and no browser tab
5
+ to open.
6
+
7
+ ```bash
8
+ pip install DocmaxV3
9
+ docmax merge a.pdf b.pdf -o combined.pdf
10
+ ```
11
+
12
+ > **Status: early development (M0).** The architecture and safety mechanisms are
13
+ > in place; the tools are being rebuilt on top of them one at a time. For a
14
+ > working tool today, use [`docmax` 2.x](https://pypi.org/project/docmax/).
15
+ > See [the roadmap](#roadmap) for what lands when.
16
+
17
+ ---
18
+
19
+ ## Why another PDF tool
20
+
21
+ The good self-hosted options — Stirling PDF and friends — are excellent, and
22
+ they all assume a browser. That means Docker, a running server, a port, and no
23
+ sensible way to use them over SSH or from a script.
24
+
25
+ DocMax assumes a terminal instead.
26
+
27
+ | | DocMax | Self-hosted web tools |
28
+ |---|---|---|
29
+ | Install | `pip install DocmaxV3` | Docker + a container |
30
+ | Interface | CLI and TUI | browser |
31
+ | Over SSH | works | needs port forwarding |
32
+ | Scripting | argv | HTTP against a running server |
33
+ | Your documents | stay on your machine | stay on your machine |
34
+
35
+ ## Two engines, one interface
36
+
37
+ Every operation can run two ways, and the choice is yours per tool:
38
+
39
+ - **Local** — offline and private. Needs the relevant dependencies installed.
40
+ - **Cloud** — no local install at all. For the handful of tools whose
41
+ dependencies are genuinely painful.
42
+
43
+ ```bash
44
+ docmax ocr scan.pdf # picks whichever is available
45
+ docmax ocr scan.pdf --engine local # force local
46
+ docmax ocr scan.pdf --engine cloud # skip installing Tesseract
47
+ ```
48
+
49
+ Cloud exists for exactly one reason — to let you use a tool without installing
50
+ its heavy dependencies. Only five tools have it (`ocr`, `compress`, `convert`,
51
+ `pdfa`, `remove-bg`), because for a pure-Python operation like `merge`,
52
+ uploading your document would be slower, less private, and pointless.
53
+
54
+ **Nothing is ever uploaded without asking.** Consent is per-tool and remembered;
55
+ `offline = true` in your config disables cloud entirely regardless of flags; and
56
+ every upload tells you what it is sending before it sends it. The cloud endpoint
57
+ is configurable, so you can point DocMax at your own server instead.
58
+
59
+ ## Your files are safe
60
+
61
+ This is the part most tools get wrong, so it is worth being specific.
62
+
63
+ - **Atomic writes.** Output goes to a temp file, gets validated, and is only then
64
+ swapped into place. A crash or Ctrl-C mid-operation leaves your destination
65
+ either untouched or absent — never half-written.
66
+ - **Your input is never the output.** `docmax merge a.pdf b.pdf -o a.pdf` is
67
+ refused, not silently obeyed.
68
+ - **Nothing is overwritten by accident.** Existing files need `--force`.
69
+ - **No tracebacks.** Every anticipated failure gives you a plain message and the
70
+ next step to take.
71
+
72
+ These are enforced by tests that run on every commit across Linux, macOS, and
73
+ Windows — not by good intentions. See
74
+ [architecture.md](docs/architecture.md#the-structural-guarantees).
75
+
76
+ ## Install
77
+
78
+ ```bash
79
+ pip install DocmaxV3 # the shell and the cloud client
80
+ pip install "DocmaxV3[ocr]" # local OCR
81
+ pip install "DocmaxV3[all]" # everything
82
+ ```
83
+
84
+ The base install is deliberately small. Heavy dependencies arrive only when you
85
+ first ask for a local engine that needs them.
86
+
87
+ Some local engines also need external programs (Ghostscript, Tesseract, Pandoc,
88
+ Poppler):
89
+
90
+ ```bash
91
+ docmax doctor # what's installed, what's missing, what needs it
92
+ ```
93
+
94
+ ## Roadmap
95
+
96
+ | | | |
97
+ |---|---|---|
98
+ | **M0** | Foundation — architecture, CI, safety mechanisms | ✅ done |
99
+ | **M1** | Core engine + `merge` as the reference implementation | in progress |
100
+ | **M2** | `split`, `rotate`, `reorder`, `pages`, `metadata`, `sanitize`, `get-info` | |
101
+ | **M3** | `compress` + a real `setup` / `doctor` | |
102
+ | **M4** | `watermark`, `stamp`, `protect`, `unlock`, `permissions` | |
103
+ | **M5** | `convert`, `to-images`, `from-images` | |
104
+ | **M6** | Cloud engines, `--json` everywhere, published benchmarks | |
105
+ | **M7** | Textual TUI + visual pickers for crop and reorder | |
106
+ | **M8** | OCR, done properly | |
107
+ | **M9** | Pipelines, resumable batch, folder watch | |
108
+ | **M10** | Local MCP server — drive DocMax from an AI agent, nothing leaves your machine | |
109
+
110
+ Benchmarks will be published in `benchmarks/` with real hardware and
111
+ methodology. No numbers appear in this README until they are measured.
112
+
113
+ ## Contributing
114
+
115
+ ```bash
116
+ git clone https://github.com/megabyte44/docmax
117
+ cd docmax
118
+ python -m venv .venv && .venv/bin/pip install -e ".[dev]"
119
+ pre-commit install
120
+
121
+ pytest && ruff check . && mypy && lint-imports
122
+ ```
123
+
124
+ Start with [docs/architecture.md](docs/architecture.md) and the
125
+ [ADRs](docs/adr/) — they explain the constraints, most of which exist for a
126
+ specific reason.
127
+
128
+ ## Licence
129
+
130
+ MIT. Every document operation is free and always will be — see
131
+ [ADR 0004](docs/adr/0004-open-core-boundary.md) for where the open-core line
132
+ sits and why.
@@ -0,0 +1,240 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ # ============================================================================
6
+ # NOTE: product identity also lives in src/docmax/core/branding.py.
7
+ # tests/hygiene/test_branding.py asserts the two stay in sync and that brand
8
+ # literals do not leak into other modules.
9
+ # ============================================================================
10
+
11
+ [project]
12
+ name = "DocmaxV3"
13
+ version = "3.0.0a7"
14
+ description = "Terminal-native document toolkit. Local-first, dual-engine, no server required."
15
+ readme = "README.md"
16
+ requires-python = ">=3.11"
17
+ authors = [{ name = "Punith Naidu" }]
18
+ maintainers = [{ name = "Punith Naidu", email = "punithmedaramitta@gmail.com" }]
19
+ license = "MIT"
20
+ license-files = ["LICENSE"]
21
+ keywords = ["pdf", "ocr", "document", "cli", "tui", "terminal", "conversion", "batch"]
22
+ classifiers = [
23
+ "Development Status :: 3 - Alpha",
24
+ "Environment :: Console",
25
+ "Intended Audience :: End Users/Desktop",
26
+ "Intended Audience :: Developers",
27
+ "Operating System :: OS Independent",
28
+ "Programming Language :: Python :: 3.11",
29
+ "Programming Language :: Python :: 3.12",
30
+ "Programming Language :: Python :: 3.13",
31
+ "Topic :: Office/Business",
32
+ "Topic :: Utilities",
33
+ "Typing :: Typed",
34
+ ]
35
+
36
+ # Base install stays light — non-negotiable #3.
37
+ # Everything here is pure Python and installs in seconds on every platform.
38
+ # Heavy deps (OpenCV, Tesseract bindings, ML models) live in extras and are
39
+ # imported lazily, never at module scope. See tests/hygiene/test_no_heavy_imports.py
40
+ dependencies = [
41
+ "typer>=0.12.0",
42
+ "rich>=13.7.0",
43
+ "pypdf>=4.2.0",
44
+ "platformdirs>=4.2.0",
45
+ "httpx>=0.27.0",
46
+ ]
47
+
48
+ [project.optional-dependencies]
49
+ # Each extra maps to the local engine of a specific tool group.
50
+ # `docmax setup` installs the external *binaries*; these are the Python bindings.
51
+ ocr = [
52
+ "pytesseract>=0.3.10",
53
+ "pdf2image>=1.17.0",
54
+ "opencv-python-headless>=4.9.0",
55
+ "numpy>=1.26.0",
56
+ ]
57
+ tables = [
58
+ "pdfplumber>=0.11.0",
59
+ "pandas>=2.2.0",
60
+ "openpyxl>=3.1.0",
61
+ ]
62
+ images = [
63
+ "Pillow>=10.3.0",
64
+ "img2pdf>=0.5.0",
65
+ ]
66
+ tui = [
67
+ "textual>=0.60.0",
68
+ ]
69
+ # Dependencies for the reference API server — the half a self-hoster deploys.
70
+ # Not in `all`: installing DocMax should never install a web framework by
71
+ # accident. Note this extra installs what the server *needs*, not the server
72
+ # itself: its code is excluded from the wheel (see packages.find below) and is
73
+ # run from a checkout.
74
+ server = [
75
+ "DocmaxV3[all]",
76
+ "fastapi>=0.111.0",
77
+ "uvicorn[standard]>=0.30.0",
78
+ "python-multipart>=0.0.9",
79
+ ]
80
+ # v2 shipped a `full` extra that silently omitted opencv, which broke the entire
81
+ # OCR path for anyone who installed it. Self-referencing extras make that class
82
+ # of mistake impossible — there is only one list.
83
+ #
84
+ # Must match [project].name exactly: "docmax" is already taken on PyPI by the
85
+ # v2 package under this same author, so "docmax[...]" here would silently
86
+ # resolve to that external package instead of self-referencing, shadowing the
87
+ # local editable install with v2's incompatible module layout.
88
+ all = [
89
+ "DocmaxV3[ocr,tables,images,tui]",
90
+ ]
91
+ dev = [
92
+ "pytest>=8.2.0",
93
+ "pytest-cov>=5.0.0",
94
+ "pytest-timeout>=2.3.0",
95
+ "hypothesis>=6.100.0",
96
+ "respx>=0.21.0",
97
+ "ruff>=0.5.0",
98
+ "mypy>=1.10.0",
99
+ "import-linter>=2.0",
100
+ "pre-commit>=3.7.0",
101
+ ]
102
+
103
+ [project.scripts]
104
+ docmax = "docmax.cli.main:app"
105
+
106
+ [project.urls]
107
+ Homepage = "https://github.com/megabyte44/docmax"
108
+ Repository = "https://github.com/megabyte44/docmax"
109
+ Issues = "https://github.com/megabyte44/docmax/issues"
110
+ Changelog = "https://github.com/megabyte44/docmax/blob/main/CHANGELOG.md"
111
+
112
+ [tool.setuptools.packages.find]
113
+ where = ["src"]
114
+ # The server is the half a self-hoster deploys from a checkout, inside an image
115
+ # that also carries Ghostscript, Tesseract, and Pandoc — none of which pip can
116
+ # install. So it has no reason to be in the wheel, and one reason not to be:
117
+ # every byte here lands in the site-packages of someone who only wanted to merge
118
+ # two PDFs. tests/hygiene/test_wheel_excludes_server.py holds the line.
119
+ exclude = ["docmax.server*"]
120
+
121
+ [tool.setuptools.package-data]
122
+ docmax = ["py.typed"]
123
+
124
+ # ============================================================================
125
+ # Ruff
126
+ # ============================================================================
127
+ [tool.ruff]
128
+ target-version = "py311"
129
+ line-length = 100
130
+ src = ["src", "tests"]
131
+
132
+ [tool.ruff.lint]
133
+ select = [
134
+ "E", "W", # pycodestyle
135
+ "F", # pyflakes
136
+ "I", # isort
137
+ "N", # pep8-naming
138
+ "UP", # pyupgrade
139
+ "B", # bugbear
140
+ "A", # builtin shadowing
141
+ "C4", # comprehensions
142
+ "PT", # pytest style
143
+ "SIM", # simplify
144
+ "RET", # return consistency
145
+ "PTH", # use pathlib, not os.path
146
+ "S", # bandit — this project shells out; we want these loud
147
+ "T20", # no stray print() in library code
148
+ "RUF",
149
+ ]
150
+ ignore = [
151
+ "E501", # line length is handled by the formatter
152
+ "S101", # assert is fine in tests
153
+ "RUF012", # ClassVar annotations on mutable defaults — noisy for our error classes
154
+ ]
155
+
156
+ [tool.ruff.lint.per-file-ignores]
157
+ # Tests may assert, use fixtures loosely, and print.
158
+ "tests/**" = ["S", "T20", "ARG", "PLR2004"]
159
+ # The CLI layer is the one place that legitimately writes to stdout.
160
+ "src/docmax/cli/**" = ["T20"]
161
+ # FastAPI's dependency-injection idiom is a call in an argument default, which
162
+ # B008 exists to catch. It is correct everywhere else.
163
+ "src/docmax/server/**" = ["B008"]
164
+
165
+ [tool.ruff.lint.isort]
166
+ known-first-party = ["docmax"]
167
+
168
+ # ============================================================================
169
+ # Mypy — strict. There is no legacy code to grandfather in.
170
+ # ============================================================================
171
+ [tool.mypy]
172
+ python_version = "3.11"
173
+ strict = true
174
+ warn_unreachable = true
175
+ warn_no_return = true
176
+ show_error_codes = true
177
+ pretty = true
178
+ files = ["src", "tests"]
179
+
180
+ # Third-party packages without type stubs. Kept as a short, explicit list so
181
+ # that adding one is a visible decision rather than a blanket ignore.
182
+ [[tool.mypy.overrides]]
183
+ module = [
184
+ "pytesseract.*",
185
+ "pdf2image.*",
186
+ "cv2.*",
187
+ "img2pdf.*",
188
+ "pdfplumber.*",
189
+ "rembg.*",
190
+ ]
191
+ ignore_missing_imports = true
192
+
193
+ # The server extra is not part of `dev`: the lint job type-checks the terminal
194
+ # tool, and a self-hosted API server should not be able to slow that down or
195
+ # break it. These two overrides are what that costs.
196
+ [[tool.mypy.overrides]]
197
+ module = [
198
+ "fastapi.*",
199
+ "starlette.*",
200
+ "uvicorn.*",
201
+ ]
202
+ ignore_missing_imports = true
203
+
204
+ [[tool.mypy.overrides]]
205
+ module = ["docmax.server.*"]
206
+ # FastAPI's route decorators are untyped when the framework itself is absent.
207
+ disallow_untyped_decorators = false
208
+
209
+ # ============================================================================
210
+ # Pytest
211
+ # ============================================================================
212
+ [tool.pytest.ini_options]
213
+ minversion = "8.0"
214
+ testpaths = ["tests"]
215
+ addopts = [
216
+ "--strict-markers",
217
+ "--strict-config",
218
+ "-ra",
219
+ ]
220
+ # No test may hang. Property tests feed malformed bytes to parsers; a hang is a
221
+ # failure mode we explicitly assert against.
222
+ timeout = 120
223
+ markers = [
224
+ "needs_binary(name): requires an external binary (gs, tesseract, pandoc, pdftoppm). Skipped when absent locally, REQUIRED in CI.",
225
+ "golden: golden-file test against the generated fixture corpus.",
226
+ "property: hypothesis-based fuzz test.",
227
+ "slow: excluded from the default run via -m 'not slow'.",
228
+ ]
229
+
230
+ [tool.coverage.run]
231
+ source = ["docmax"]
232
+ branch = true
233
+
234
+ [tool.coverage.report]
235
+ exclude_lines = [
236
+ "pragma: no cover",
237
+ "if TYPE_CHECKING:",
238
+ "raise NotImplementedError",
239
+ "@overload",
240
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+