docforge-sdk 0.1.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.
- docforge_sdk-0.1.0/.gitignore +85 -0
- docforge_sdk-0.1.0/.python-version +1 -0
- docforge_sdk-0.1.0/LICENSE +21 -0
- docforge_sdk-0.1.0/PKG-INFO +108 -0
- docforge_sdk-0.1.0/README.md +85 -0
- docforge_sdk-0.1.0/docforge_sdk/__init__.py +161 -0
- docforge_sdk-0.1.0/docforge_sdk/_exceptions.py +108 -0
- docforge_sdk-0.1.0/docforge_sdk/_requestspec.py +34 -0
- docforge_sdk-0.1.0/docforge_sdk/_transport_async.py +168 -0
- docforge_sdk-0.1.0/docforge_sdk/_transport_base.py +141 -0
- docforge_sdk-0.1.0/docforge_sdk/_transport_sync.py +168 -0
- docforge_sdk-0.1.0/docforge_sdk/_version.py +5 -0
- docforge_sdk-0.1.0/docforge_sdk/client.py +131 -0
- docforge_sdk-0.1.0/docforge_sdk/models/__init__.py +132 -0
- docforge_sdk-0.1.0/docforge_sdk/models/_shared.py +121 -0
- docforge_sdk-0.1.0/docforge_sdk/models/auth.py +130 -0
- docforge_sdk-0.1.0/docforge_sdk/models/blobs.py +25 -0
- docforge_sdk-0.1.0/docforge_sdk/models/collections.py +142 -0
- docforge_sdk-0.1.0/docforge_sdk/models/documents.py +49 -0
- docforge_sdk-0.1.0/docforge_sdk/models/explorer.py +238 -0
- docforge_sdk-0.1.0/docforge_sdk/models/health.py +20 -0
- docforge_sdk-0.1.0/docforge_sdk/models/ir.py +139 -0
- docforge_sdk-0.1.0/docforge_sdk/models/jobs.py +100 -0
- docforge_sdk-0.1.0/docforge_sdk/models/pipelines.py +182 -0
- docforge_sdk-0.1.0/docforge_sdk/models/search.py +110 -0
- docforge_sdk-0.1.0/docforge_sdk/py.typed +0 -0
- docforge_sdk-0.1.0/docforge_sdk/resources/__init__.py +53 -0
- docforge_sdk-0.1.0/docforge_sdk/resources/_base.py +46 -0
- docforge_sdk-0.1.0/docforge_sdk/resources/auth.py +264 -0
- docforge_sdk-0.1.0/docforge_sdk/resources/blobs.py +63 -0
- docforge_sdk-0.1.0/docforge_sdk/resources/collections.py +204 -0
- docforge_sdk-0.1.0/docforge_sdk/resources/documents.py +153 -0
- docforge_sdk-0.1.0/docforge_sdk/resources/explorer.py +342 -0
- docforge_sdk-0.1.0/docforge_sdk/resources/health.py +53 -0
- docforge_sdk-0.1.0/docforge_sdk/resources/jobs.py +161 -0
- docforge_sdk-0.1.0/docforge_sdk/resources/pipelines.py +291 -0
- docforge_sdk-0.1.0/docforge_sdk/resources/search.py +70 -0
- docforge_sdk-0.1.0/pyproject.toml +83 -0
- docforge_sdk-0.1.0/tests/__init__.py +0 -0
- docforge_sdk-0.1.0/tests/check_schema_drift.py +115 -0
- docforge_sdk-0.1.0/tests/live/__init__.py +0 -0
- docforge_sdk-0.1.0/tests/live/test_openapi_parity_live.py +53 -0
- docforge_sdk-0.1.0/tests/openapi_snapshot.json +1 -0
- docforge_sdk-0.1.0/tests/parity_map.py +104 -0
- docforge_sdk-0.1.0/tests/unit/__init__.py +0 -0
- docforge_sdk-0.1.0/tests/unit/test_auth.py +135 -0
- docforge_sdk-0.1.0/tests/unit/test_blobs.py +42 -0
- docforge_sdk-0.1.0/tests/unit/test_collections.py +91 -0
- docforge_sdk-0.1.0/tests/unit/test_documents.py +53 -0
- docforge_sdk-0.1.0/tests/unit/test_explorer.py +96 -0
- docforge_sdk-0.1.0/tests/unit/test_health.py +37 -0
- docforge_sdk-0.1.0/tests/unit/test_jobs.py +54 -0
- docforge_sdk-0.1.0/tests/unit/test_models_offline_parity.py +48 -0
- docforge_sdk-0.1.0/tests/unit/test_pipelines.py +74 -0
- docforge_sdk-0.1.0/tests/unit/test_resource_parity.py +55 -0
- docforge_sdk-0.1.0/tests/unit/test_search.py +59 -0
- docforge_sdk-0.1.0/tests/unit/test_transport.py +131 -0
- docforge_sdk-0.1.0/uv.lock +504 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# ── Python ────────────────────────────────────────────────
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.pyo
|
|
5
|
+
*.pyd
|
|
6
|
+
.Python
|
|
7
|
+
*.egg-info/
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
*.egg
|
|
11
|
+
.eggs/
|
|
12
|
+
|
|
13
|
+
# ── Virtual environments ───────────────────────────────────
|
|
14
|
+
.venv/
|
|
15
|
+
venv/
|
|
16
|
+
env/
|
|
17
|
+
ENV/
|
|
18
|
+
|
|
19
|
+
# ── uv ────────────────────────────────────────────────────
|
|
20
|
+
.uv/
|
|
21
|
+
|
|
22
|
+
# ── Secrets / credentials ─────────────────────────────────
|
|
23
|
+
services/**/.env
|
|
24
|
+
*.env
|
|
25
|
+
!services/**/.env.example
|
|
26
|
+
!.env.example
|
|
27
|
+
# SeaweedFS S3 identity (real secret) — track only the placeholder template.
|
|
28
|
+
services/**/s3_config.json
|
|
29
|
+
!services/**/s3_config.json.example
|
|
30
|
+
|
|
31
|
+
# ── Logs ──────────────────────────────────────────────────
|
|
32
|
+
logs/
|
|
33
|
+
*.log
|
|
34
|
+
|
|
35
|
+
# ── Node / frontend build artifacts (location-independent) ──
|
|
36
|
+
# Globbed so they match wherever the frontend lives (now src/docforge-rework/app/frontend/).
|
|
37
|
+
**/node_modules/
|
|
38
|
+
**/frontend/dist/
|
|
39
|
+
# Stale .js outputs that shadow .tsx/.ts source — Vite resolves them with priority
|
|
40
|
+
# and serves an old bundle. We're TS-only (tsconfig has noEmit); any .js under a
|
|
41
|
+
# frontend src/ is build artefact noise.
|
|
42
|
+
**/frontend/src/**/*.js
|
|
43
|
+
**/frontend/src/**/*.js.map
|
|
44
|
+
# NOTE: src/api/generated.ts is NOW committed (tracked) so the build is reproducible
|
|
45
|
+
# without a live backend — regenerate it with `npm run gen:types` after schema changes.
|
|
46
|
+
|
|
47
|
+
# ── IDE / OS ──────────────────────────────────────────────
|
|
48
|
+
.idea/
|
|
49
|
+
.vscode/
|
|
50
|
+
*.swp
|
|
51
|
+
*.swo
|
|
52
|
+
.DS_Store
|
|
53
|
+
Thumbs.db
|
|
54
|
+
|
|
55
|
+
# ── Claude Code / AI dev tooling (kept LOCAL, never published) ──
|
|
56
|
+
# The whole .claude/ tree (agents, rules, commands, agent-memory, session data, knowledge graph)
|
|
57
|
+
# and the MCP client config are internal AI-assisted-workflow tooling — not part of the public repo.
|
|
58
|
+
.claude/
|
|
59
|
+
.mcp.json
|
|
60
|
+
|
|
61
|
+
# ── Alembic / migrations (keep structure, not generated) ──
|
|
62
|
+
# src/docforge-rework/migrations/versions/*.py # comment in to exclude
|
|
63
|
+
|
|
64
|
+
# ── Test artifacts ────────────────────────────────────────
|
|
65
|
+
.pytest_cache/
|
|
66
|
+
.coverage
|
|
67
|
+
htmlcov/
|
|
68
|
+
# Note: the synthetic test corpus under src/docforge-rework/tests/corpus/documents/<ext>/ IS committed
|
|
69
|
+
# (deterministic, loaded at test time); it is regenerated via tests/corpus/generation/ when builders change.
|
|
70
|
+
|
|
71
|
+
# Vite dependency pre-bundling cache (regenerated by the dev server)
|
|
72
|
+
**/.vite/
|
|
73
|
+
|
|
74
|
+
# Playwright MCP session artifacts (snapshots / console logs from browser-driven checks)
|
|
75
|
+
.playwright-mcp/
|
|
76
|
+
|
|
77
|
+
# The pipeline BUILD module (blob models + PipelineBuilder) is SOURCE, not a build
|
|
78
|
+
# artifact - re-include it from the global build/ rule above.
|
|
79
|
+
!src/docforge-rework/shared/libs/pipelines/build/
|
|
80
|
+
!src/docforge-rework/shared/libs/pipelines/build/**
|
|
81
|
+
|
|
82
|
+
# The build/ unit-test package mirrors that source module - also SOURCE, not an artifact.
|
|
83
|
+
!src/docforge-rework/tests/units/build/
|
|
84
|
+
!src/docforge-rework/tests/units/build/**
|
|
85
|
+
src/docforge-rework/app/frontend/scripts/node_modules/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Florian Barré
|
|
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,108 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: docforge-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Typed async + sync Python client for the DocForge REST API (standalone, zero server deps).
|
|
5
|
+
Project-URL: Homepage, https://github.com/Florian-BARRE/docforge
|
|
6
|
+
Project-URL: Repository, https://github.com/Florian-BARRE/docforge
|
|
7
|
+
Project-URL: Issues, https://github.com/Florian-BARRE/docforge/issues
|
|
8
|
+
Author: Florian Barré
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: api-client,async,client,docforge,document-intelligence,rag,retrieval,sdk
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Python: >=3.12
|
|
20
|
+
Requires-Dist: httpx>=0.28
|
|
21
|
+
Requires-Dist: pydantic>=2.7
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# docforge-sdk
|
|
25
|
+
|
|
26
|
+
A typed Python client for the [DocForge](https://github.com/Florian-BARRE/docforge) REST API. It
|
|
27
|
+
ships **both** an asynchronous and a synchronous client with an identical surface, is fully
|
|
28
|
+
type-hinted (`py.typed`), and has **zero dependency on the DocForge server tree** — it is a
|
|
29
|
+
clean-room client that talks to the API over HTTP only (`httpx` + `pydantic` + hand-written models
|
|
30
|
+
that mirror the public REST contract), so it can be vendored or published independently.
|
|
31
|
+
|
|
32
|
+
## Install
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install docforge-sdk
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Async usage
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
import asyncio
|
|
42
|
+
|
|
43
|
+
from docforge_sdk import AsyncClient, SearchRequest
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
async def main() -> None:
|
|
47
|
+
async with AsyncClient("http://localhost:10040", api_token="df_root_...") as client:
|
|
48
|
+
collections = await client.collections.list()
|
|
49
|
+
for collection in collections:
|
|
50
|
+
print(collection.id, collection.name)
|
|
51
|
+
|
|
52
|
+
hits = await client.search.search(
|
|
53
|
+
collections[0].id,
|
|
54
|
+
SearchRequest(query="quarterly revenue", limit=5),
|
|
55
|
+
)
|
|
56
|
+
for hit in hits.hits:
|
|
57
|
+
print(hit.score, hit.text)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
asyncio.run(main())
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Sync usage
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from docforge_sdk import Client, SearchRequest
|
|
67
|
+
|
|
68
|
+
with Client("http://localhost:10040", api_token="df_root_...") as client:
|
|
69
|
+
collections = client.collections.list()
|
|
70
|
+
hits = client.search.search(
|
|
71
|
+
collections[0].id,
|
|
72
|
+
SearchRequest(query="quarterly revenue", limit=5),
|
|
73
|
+
)
|
|
74
|
+
for hit in hits.hits:
|
|
75
|
+
print(hit.score, hit.text)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The two clients expose the same resources and method signatures; the sync methods are the async ones
|
|
79
|
+
without `await`. Available resource groups: `auth`, `health`, `collections`, `documents`, `explorer`,
|
|
80
|
+
`search`, `jobs`, `blobs`, `pipelines`.
|
|
81
|
+
|
|
82
|
+
## License
|
|
83
|
+
|
|
84
|
+
MIT — see [LICENSE](LICENSE). This SDK is deliberately licensed **MIT even though the parent DocForge
|
|
85
|
+
repository is GPLv3**: it is a standalone, clean-room client (HTTP models only, no server code), so a
|
|
86
|
+
permissive per-directory license is intentional and lets any project depend on it freely.
|
|
87
|
+
|
|
88
|
+
## Publishing (maintainers)
|
|
89
|
+
|
|
90
|
+
Releases publish to PyPI via **Trusted Publishing (OIDC)** — there is no API token stored in the
|
|
91
|
+
repo. To cut a release, tag a commit with the `sdk-v<version>` prefix (the version must match
|
|
92
|
+
`docforge_sdk/_version.py`) and push the tag:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
git tag sdk-v0.1.0
|
|
96
|
+
git push origin sdk-v0.1.0
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The `.github/workflows/release-sdk.yml` workflow then builds and uploads the sdist + wheel.
|
|
100
|
+
|
|
101
|
+
**One-time PyPI setup** (done once by the maintainer, before the first release):
|
|
102
|
+
|
|
103
|
+
1. Reserve the project name `docforge-sdk` on PyPI.
|
|
104
|
+
2. Under the project's *Publishing* settings, add a **GitHub trusted publisher** with:
|
|
105
|
+
- Owner: `Florian-BARRE`
|
|
106
|
+
- Repository: `docforge`
|
|
107
|
+
- Workflow name: `release-sdk.yml`
|
|
108
|
+
- Environment: `pypi`
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# docforge-sdk
|
|
2
|
+
|
|
3
|
+
A typed Python client for the [DocForge](https://github.com/Florian-BARRE/docforge) REST API. It
|
|
4
|
+
ships **both** an asynchronous and a synchronous client with an identical surface, is fully
|
|
5
|
+
type-hinted (`py.typed`), and has **zero dependency on the DocForge server tree** — it is a
|
|
6
|
+
clean-room client that talks to the API over HTTP only (`httpx` + `pydantic` + hand-written models
|
|
7
|
+
that mirror the public REST contract), so it can be vendored or published independently.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install docforge-sdk
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Async usage
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
import asyncio
|
|
19
|
+
|
|
20
|
+
from docforge_sdk import AsyncClient, SearchRequest
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
async def main() -> None:
|
|
24
|
+
async with AsyncClient("http://localhost:10040", api_token="df_root_...") as client:
|
|
25
|
+
collections = await client.collections.list()
|
|
26
|
+
for collection in collections:
|
|
27
|
+
print(collection.id, collection.name)
|
|
28
|
+
|
|
29
|
+
hits = await client.search.search(
|
|
30
|
+
collections[0].id,
|
|
31
|
+
SearchRequest(query="quarterly revenue", limit=5),
|
|
32
|
+
)
|
|
33
|
+
for hit in hits.hits:
|
|
34
|
+
print(hit.score, hit.text)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
asyncio.run(main())
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Sync usage
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from docforge_sdk import Client, SearchRequest
|
|
44
|
+
|
|
45
|
+
with Client("http://localhost:10040", api_token="df_root_...") as client:
|
|
46
|
+
collections = client.collections.list()
|
|
47
|
+
hits = client.search.search(
|
|
48
|
+
collections[0].id,
|
|
49
|
+
SearchRequest(query="quarterly revenue", limit=5),
|
|
50
|
+
)
|
|
51
|
+
for hit in hits.hits:
|
|
52
|
+
print(hit.score, hit.text)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The two clients expose the same resources and method signatures; the sync methods are the async ones
|
|
56
|
+
without `await`. Available resource groups: `auth`, `health`, `collections`, `documents`, `explorer`,
|
|
57
|
+
`search`, `jobs`, `blobs`, `pipelines`.
|
|
58
|
+
|
|
59
|
+
## License
|
|
60
|
+
|
|
61
|
+
MIT — see [LICENSE](LICENSE). This SDK is deliberately licensed **MIT even though the parent DocForge
|
|
62
|
+
repository is GPLv3**: it is a standalone, clean-room client (HTTP models only, no server code), so a
|
|
63
|
+
permissive per-directory license is intentional and lets any project depend on it freely.
|
|
64
|
+
|
|
65
|
+
## Publishing (maintainers)
|
|
66
|
+
|
|
67
|
+
Releases publish to PyPI via **Trusted Publishing (OIDC)** — there is no API token stored in the
|
|
68
|
+
repo. To cut a release, tag a commit with the `sdk-v<version>` prefix (the version must match
|
|
69
|
+
`docforge_sdk/_version.py`) and push the tag:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
git tag sdk-v0.1.0
|
|
73
|
+
git push origin sdk-v0.1.0
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The `.github/workflows/release-sdk.yml` workflow then builds and uploads the sdist + wheel.
|
|
77
|
+
|
|
78
|
+
**One-time PyPI setup** (done once by the maintainer, before the first release):
|
|
79
|
+
|
|
80
|
+
1. Reserve the project name `docforge-sdk` on PyPI.
|
|
81
|
+
2. Under the project's *Publishing* settings, add a **GitHub trusted publisher** with:
|
|
82
|
+
- Owner: `Florian-BARRE`
|
|
83
|
+
- Repository: `docforge`
|
|
84
|
+
- Workflow name: `release-sdk.yml`
|
|
85
|
+
- Environment: `pypi`
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# ------------------- Exceptions ------------------- #
|
|
2
|
+
from ._exceptions import (
|
|
3
|
+
APIConnectionError,
|
|
4
|
+
APIStatusError,
|
|
5
|
+
APITimeoutError,
|
|
6
|
+
AuthError,
|
|
7
|
+
ConflictError,
|
|
8
|
+
DocForgeError,
|
|
9
|
+
NotFoundError,
|
|
10
|
+
UnprocessableError,
|
|
11
|
+
)
|
|
12
|
+
from ._version import __version__
|
|
13
|
+
|
|
14
|
+
# ------------------- Clients ------------------- #
|
|
15
|
+
from .client import AsyncClient, Client
|
|
16
|
+
|
|
17
|
+
# ------------------- Shared vocabulary ------------------- #
|
|
18
|
+
from .models._shared import (
|
|
19
|
+
Capability,
|
|
20
|
+
DocumentStatus,
|
|
21
|
+
EnrichmentKind,
|
|
22
|
+
EnrichmentStatus,
|
|
23
|
+
FieldOrigin,
|
|
24
|
+
FieldScope,
|
|
25
|
+
FieldType,
|
|
26
|
+
KeyPermissions,
|
|
27
|
+
SourceKind,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# ------------------- Auth models ------------------- #
|
|
31
|
+
from .models.auth import CreatedKey, CreateKeyRequest, KeyInfo, RotateKeyRequest
|
|
32
|
+
|
|
33
|
+
# ------------------- Blobs models ------------------- #
|
|
34
|
+
from .models.blobs import BlobContent
|
|
35
|
+
|
|
36
|
+
# ------------------- Collections models ------------------- #
|
|
37
|
+
from .models.collections import (
|
|
38
|
+
CollectionModel,
|
|
39
|
+
CreateCollectionRequest,
|
|
40
|
+
FieldSpec,
|
|
41
|
+
UpdateCollectionRequest,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# ------------------- Documents models ------------------- #
|
|
45
|
+
from .models.documents import DocumentEnabledResponse, EnabledPatch, UploadAccepted
|
|
46
|
+
|
|
47
|
+
# ------------------- Explorer models ------------------- #
|
|
48
|
+
from .models.explorer import (
|
|
49
|
+
BulkChunkEnabledPatch,
|
|
50
|
+
BulkChunkEnabledResponse,
|
|
51
|
+
ChunkEnabledPatch,
|
|
52
|
+
ChunkEnabledResult,
|
|
53
|
+
ChunkInfo,
|
|
54
|
+
DocumentDetail,
|
|
55
|
+
DocumentListItem,
|
|
56
|
+
MetadataValue,
|
|
57
|
+
PageInfo,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# ------------------- Health models ------------------- #
|
|
61
|
+
from .models.health import HealthStatus
|
|
62
|
+
|
|
63
|
+
# ------------------- IR models ------------------- #
|
|
64
|
+
from .models.ir import DocumentIRModel, IRBlock, IREnrichment, IRFigure, IRTable
|
|
65
|
+
|
|
66
|
+
# ------------------- Jobs models ------------------- #
|
|
67
|
+
from .models.jobs import JobEvent, JobStatus, JobTrace, WorkerActivity, WorkersLive
|
|
68
|
+
|
|
69
|
+
# ------------------- Pipelines models ------------------- #
|
|
70
|
+
from .models.pipelines import (
|
|
71
|
+
EditResponse,
|
|
72
|
+
InspectResponse,
|
|
73
|
+
PipelineDesignResponse,
|
|
74
|
+
PipelineIndexResponse,
|
|
75
|
+
PipelineSurface,
|
|
76
|
+
StageApplyResponse,
|
|
77
|
+
StageViewResponse,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# ------------------- Search models ------------------- #
|
|
81
|
+
from .models.search import SearchHit, SearchRequest, SearchResponse, SearchTarget
|
|
82
|
+
|
|
83
|
+
# ------------------- Public API ------------------- #
|
|
84
|
+
__all__ = [
|
|
85
|
+
"__version__",
|
|
86
|
+
# Clients
|
|
87
|
+
"AsyncClient",
|
|
88
|
+
"Client",
|
|
89
|
+
# Shared vocabulary
|
|
90
|
+
"Capability",
|
|
91
|
+
"KeyPermissions",
|
|
92
|
+
"FieldType",
|
|
93
|
+
"FieldOrigin",
|
|
94
|
+
"FieldScope",
|
|
95
|
+
"SourceKind",
|
|
96
|
+
"DocumentStatus",
|
|
97
|
+
"EnrichmentKind",
|
|
98
|
+
"EnrichmentStatus",
|
|
99
|
+
# Auth
|
|
100
|
+
"CreateKeyRequest",
|
|
101
|
+
"RotateKeyRequest",
|
|
102
|
+
"CreatedKey",
|
|
103
|
+
"KeyInfo",
|
|
104
|
+
# Health
|
|
105
|
+
"HealthStatus",
|
|
106
|
+
# Collections
|
|
107
|
+
"FieldSpec",
|
|
108
|
+
"CollectionModel",
|
|
109
|
+
"CreateCollectionRequest",
|
|
110
|
+
"UpdateCollectionRequest",
|
|
111
|
+
# Documents
|
|
112
|
+
"UploadAccepted",
|
|
113
|
+
"EnabledPatch",
|
|
114
|
+
"DocumentEnabledResponse",
|
|
115
|
+
# Explorer
|
|
116
|
+
"MetadataValue",
|
|
117
|
+
"DocumentListItem",
|
|
118
|
+
"DocumentDetail",
|
|
119
|
+
"PageInfo",
|
|
120
|
+
"ChunkInfo",
|
|
121
|
+
"ChunkEnabledPatch",
|
|
122
|
+
"BulkChunkEnabledPatch",
|
|
123
|
+
"ChunkEnabledResult",
|
|
124
|
+
"BulkChunkEnabledResponse",
|
|
125
|
+
# IR
|
|
126
|
+
"IRBlock",
|
|
127
|
+
"IRTable",
|
|
128
|
+
"IRFigure",
|
|
129
|
+
"IREnrichment",
|
|
130
|
+
"DocumentIRModel",
|
|
131
|
+
# Search
|
|
132
|
+
"SearchTarget",
|
|
133
|
+
"SearchRequest",
|
|
134
|
+
"SearchHit",
|
|
135
|
+
"SearchResponse",
|
|
136
|
+
# Jobs
|
|
137
|
+
"JobStatus",
|
|
138
|
+
"JobEvent",
|
|
139
|
+
"JobTrace",
|
|
140
|
+
"WorkerActivity",
|
|
141
|
+
"WorkersLive",
|
|
142
|
+
# Blobs
|
|
143
|
+
"BlobContent",
|
|
144
|
+
# Pipelines
|
|
145
|
+
"PipelineSurface",
|
|
146
|
+
"PipelineIndexResponse",
|
|
147
|
+
"PipelineDesignResponse",
|
|
148
|
+
"InspectResponse",
|
|
149
|
+
"EditResponse",
|
|
150
|
+
"StageViewResponse",
|
|
151
|
+
"StageApplyResponse",
|
|
152
|
+
# Exceptions
|
|
153
|
+
"DocForgeError",
|
|
154
|
+
"APIConnectionError",
|
|
155
|
+
"APITimeoutError",
|
|
156
|
+
"APIStatusError",
|
|
157
|
+
"AuthError",
|
|
158
|
+
"NotFoundError",
|
|
159
|
+
"ConflictError",
|
|
160
|
+
"UnprocessableError",
|
|
161
|
+
]
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# ====== Code Summary ======
|
|
2
|
+
# The public exception hierarchy for the SDK. Every failure a caller can catch descends from
|
|
3
|
+
# ``DocForgeError``. Transport-level failures (no connection, timeout) and HTTP error statuses map to
|
|
4
|
+
# dedicated subclasses so callers can branch on failure kind without inspecting raw httpx objects.
|
|
5
|
+
|
|
6
|
+
# ====== Standard Library Imports ======
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
# ====== Third-Party Library Imports ======
|
|
10
|
+
import httpx
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class DocForgeError(Exception):
|
|
14
|
+
"""Base class for every error raised by the DocForge SDK."""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class APIConnectionError(DocForgeError):
|
|
18
|
+
"""Raised when the API could not be reached (DNS, refused connection, network drop)."""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class APITimeoutError(APIConnectionError):
|
|
22
|
+
"""Raised when a request exceeded the configured timeout before a response arrived."""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class APIStatusError(DocForgeError):
|
|
26
|
+
"""
|
|
27
|
+
Raised when the API returned a 4xx/5xx HTTP status.
|
|
28
|
+
|
|
29
|
+
Attributes:
|
|
30
|
+
status_code (int): The HTTP status code returned by the API.
|
|
31
|
+
body (Any): The parsed response body (JSON when decodable, else raw text) — an opaque,
|
|
32
|
+
server-shaped error payload.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __init__(self, message: str, *, status_code: int, body: Any) -> None:
|
|
36
|
+
"""
|
|
37
|
+
Initialize the status error with the failing code and response body.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
message (str): Human-readable summary of the failure.
|
|
41
|
+
status_code (int): The HTTP status code returned by the API.
|
|
42
|
+
body (Any): The parsed response body (opaque server error payload).
|
|
43
|
+
"""
|
|
44
|
+
super().__init__(message)
|
|
45
|
+
self.status_code: int = status_code
|
|
46
|
+
self.body: Any = body
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class AuthError(APIStatusError):
|
|
50
|
+
"""Raised on 401 (unauthenticated) or 403 (unauthorized) responses."""
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class NotFoundError(APIStatusError):
|
|
54
|
+
"""Raised on 404 responses (the target resource does not exist)."""
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class ConflictError(APIStatusError):
|
|
58
|
+
"""Raised on 409 responses (the request conflicts with the resource's current state)."""
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class UnprocessableError(APIStatusError):
|
|
62
|
+
"""Raised on 422 responses (the request body failed server-side validation)."""
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# Maps an HTTP status code to the most specific exception class for it.
|
|
66
|
+
_STATUS_TO_EXCEPTION: dict[int, type[APIStatusError]] = {
|
|
67
|
+
401: AuthError,
|
|
68
|
+
403: AuthError,
|
|
69
|
+
404: NotFoundError,
|
|
70
|
+
409: ConflictError,
|
|
71
|
+
422: UnprocessableError,
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def exception_from_response(response: httpx.Response) -> APIStatusError:
|
|
76
|
+
"""
|
|
77
|
+
Build the most specific ``APIStatusError`` for an errored HTTP response.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
response (httpx.Response): The response whose status is 4xx/5xx.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
APIStatusError: A ``NotFoundError`` / ``AuthError`` / ``ConflictError`` /
|
|
84
|
+
``UnprocessableError`` when the status is recognised, else a plain ``APIStatusError``.
|
|
85
|
+
"""
|
|
86
|
+
# 1. Decode the body as JSON when possible; fall back to raw text for non-JSON errors.
|
|
87
|
+
try:
|
|
88
|
+
body: Any = response.json()
|
|
89
|
+
except ValueError:
|
|
90
|
+
body = response.text
|
|
91
|
+
|
|
92
|
+
# 2. Pick the dedicated subclass for this status, defaulting to the generic status error.
|
|
93
|
+
exception_class = _STATUS_TO_EXCEPTION.get(response.status_code, APIStatusError)
|
|
94
|
+
message = f"API request failed with status {response.status_code}"
|
|
95
|
+
return exception_class(message, status_code=response.status_code, body=body)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
__all__ = [
|
|
99
|
+
"DocForgeError",
|
|
100
|
+
"APIConnectionError",
|
|
101
|
+
"APITimeoutError",
|
|
102
|
+
"APIStatusError",
|
|
103
|
+
"AuthError",
|
|
104
|
+
"NotFoundError",
|
|
105
|
+
"ConflictError",
|
|
106
|
+
"UnprocessableError",
|
|
107
|
+
"exception_from_response",
|
|
108
|
+
]
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# ====== Code Summary ======
|
|
2
|
+
# The immutable description of a single HTTP call. A RequestSpec is pure data — it carries the method,
|
|
3
|
+
# API-relative path and payload, and performs no I/O. Resource classes build specs; transports execute
|
|
4
|
+
# them. Centralising URL/body shape here keeps it out of the async/sync transport bodies.
|
|
5
|
+
|
|
6
|
+
# ====== Standard Library Imports ======
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass(frozen=True, slots=True)
|
|
12
|
+
class RequestSpec:
|
|
13
|
+
"""
|
|
14
|
+
An immutable, I/O-free description of one API request.
|
|
15
|
+
|
|
16
|
+
The ``json`` and ``files`` payloads are typed ``Any`` because they are opaque, endpoint-shaped
|
|
17
|
+
bodies already serialised by the calling resource (a model dump or an httpx multipart mapping).
|
|
18
|
+
|
|
19
|
+
Attributes:
|
|
20
|
+
method (str): The HTTP method (e.g. ``"GET"``, ``"POST"``, ``"DELETE"``).
|
|
21
|
+
path (str): The path relative to the API root (e.g. ``"/auth/keys"``).
|
|
22
|
+
params (dict[str, Any] | None): Query parameters; ``None`` values are dropped at execution.
|
|
23
|
+
json (Any): The JSON request body, or ``None`` for bodyless requests.
|
|
24
|
+
files (Any): The multipart file mapping for uploads, or ``None``.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
method: str
|
|
28
|
+
path: str
|
|
29
|
+
params: dict[str, Any] | None = None
|
|
30
|
+
json: Any = None
|
|
31
|
+
files: Any = None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
__all__ = ["RequestSpec"]
|