doc-cheap 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.
- doc_cheap-0.1.0/.gitignore +11 -0
- doc_cheap-0.1.0/CHANGELOG.md +7 -0
- doc_cheap-0.1.0/LICENSE +21 -0
- doc_cheap-0.1.0/PKG-INFO +169 -0
- doc_cheap-0.1.0/README.md +134 -0
- doc_cheap-0.1.0/pyproject.toml +68 -0
- doc_cheap-0.1.0/src/doc_cheap/__init__.py +99 -0
- doc_cheap-0.1.0/src/doc_cheap/_client.py +284 -0
- doc_cheap-0.1.0/src/doc_cheap/_errors.py +184 -0
- doc_cheap-0.1.0/src/doc_cheap/_types.py +177 -0
- doc_cheap-0.1.0/src/doc_cheap/_version.py +1 -0
- doc_cheap-0.1.0/src/doc_cheap/py.typed +0 -0
- doc_cheap-0.1.0/tests/__init__.py +0 -0
- doc_cheap-0.1.0/tests/conftest.py +55 -0
- doc_cheap-0.1.0/tests/test_client.py +264 -0
- doc_cheap-0.1.0/tests/test_errors.py +150 -0
doc_cheap-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Document Cheap Inc.
|
|
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.
|
doc_cheap-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: doc-cheap
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Typed Python client for the doc.cheap document-recognition API: read passports, ID cards and driver's licences into JSON.
|
|
5
|
+
Project-URL: Homepage, https://doc.cheap
|
|
6
|
+
Project-URL: Documentation, https://doc.cheap/docs
|
|
7
|
+
Project-URL: Source, https://gitlab.com/doccheap/doc-cheap-python
|
|
8
|
+
Project-URL: Changelog, https://gitlab.com/doccheap/doc-cheap-python/-/blob/main/CHANGELOG.md
|
|
9
|
+
Author-email: Teoh Chin Heng <admin@doc.cheap>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: doc.cheap,document-recognition,id-card,kyc,mrz,ocr,passport
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Requires-Dist: httpx<1,>=0.27
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: mypy>=1.11; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest-cov>=5; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
30
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
31
|
+
Provides-Extra: test
|
|
32
|
+
Requires-Dist: pytest-cov>=5; extra == 'test'
|
|
33
|
+
Requires-Dist: pytest>=8; extra == 'test'
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
|
|
36
|
+
# doc-cheap
|
|
37
|
+
|
|
38
|
+
[](https://pypi.org/project/doc-cheap/)
|
|
39
|
+
|
|
40
|
+
The Python client for [doc.cheap](https://doc.cheap): it sends a photo or scan
|
|
41
|
+
of a passport, national ID card or driving licence to the doc.cheap API and
|
|
42
|
+
returns the printed fields – name, date of birth, document number, expiry, the
|
|
43
|
+
machine-readable zone – as typed dictionaries.
|
|
44
|
+
|
|
45
|
+
One recognised document costs one credit, $0.01. Registering gives 100 free
|
|
46
|
+
documents every month. An unreadable image, an empty frame or an unsupported
|
|
47
|
+
document type costs nothing, and every answer says whether it was billed.
|
|
48
|
+
|
|
49
|
+
The package needs Python 3.10 or later and depends only on
|
|
50
|
+
[httpx](https://www.python-httpx.org/).
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
pip install doc-cheap
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Quick start
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from doc_cheap import SANDBOX_KEY, Client
|
|
62
|
+
|
|
63
|
+
with Client(SANDBOX_KEY) as client:
|
|
64
|
+
scan = client.recognize(path="passport.jpg")
|
|
65
|
+
|
|
66
|
+
print("status:", scan["meta"]["status"], "billed:", scan["meta"]["billed"])
|
|
67
|
+
if scan["holder"] and scan["holder"]["full_name"]:
|
|
68
|
+
print("holder:", scan["holder"]["full_name"])
|
|
69
|
+
if scan["document"] and scan["document"]["expiry_date"]:
|
|
70
|
+
print("expires:", scan["document"]["expiry_date"])
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## API keys
|
|
74
|
+
|
|
75
|
+
- **Live key** – `sk_live_…`, created in the
|
|
76
|
+
[doc.cheap cabinet](https://doc.cheap/docs/concepts/api-keys-and-sessions).
|
|
77
|
+
- **Sandbox key** – `sk_sandbox_public` (the `doc_cheap.SANDBOX_KEY` constant)
|
|
78
|
+
works without an account. It gives 10 free recognised documents per address
|
|
79
|
+
in all, and at most 10 requests per address an hour, whatever their answer.
|
|
80
|
+
|
|
81
|
+
`Client()` without a key reads it from the `DOC_CHEAP_API_KEY` environment
|
|
82
|
+
variable, which keeps a live key out of source code. The key is sent as a
|
|
83
|
+
Bearer token.
|
|
84
|
+
|
|
85
|
+
## Methods
|
|
86
|
+
|
|
87
|
+
| Method | Request | What it does |
|
|
88
|
+
| --- | --- | --- |
|
|
89
|
+
| `recognize` | `POST /v1/scans` | Reads one JPEG or PNG image, from a file (`path`), raw bytes (`image`) or base64 (`image_base64`), with an optional `reference` label, `idempotency_key`, `expect_country`, `return_portrait` and `retain_hours`. |
|
|
90
|
+
| `get_scan` | `GET /v1/scans/{id}` | Returns a stored result. |
|
|
91
|
+
| `list_scans` | `GET /v1/scans` | Returns one page of stored results; pass `next_cursor` back as `cursor` for the next page. |
|
|
92
|
+
| `delete_scan` | `DELETE /v1/scans/{id}` | Deletes a stored result. |
|
|
93
|
+
| `usage` | `GET /v1/usage` | Returns this month's free credits, the paid credits, the credits spent and the scan counters. |
|
|
94
|
+
|
|
95
|
+
An image that holds no readable document is not an error: the scan comes back
|
|
96
|
+
with a status such as `unreadable` or `no_document_found` and `billed` set to
|
|
97
|
+
`False`.
|
|
98
|
+
|
|
99
|
+
**Stored results.** A result is stored only when the scan was made with a live
|
|
100
|
+
key under a non-zero retention window, and only until that window ends. Under
|
|
101
|
+
the sandbox key nothing is stored, so `get_scan` and `delete_scan` raise
|
|
102
|
+
`NotFoundError`. None of `get_scan`, `delete_scan` or `usage` charges a credit.
|
|
103
|
+
|
|
104
|
+
## Errors
|
|
105
|
+
|
|
106
|
+
Every exception the package raises is a `doc_cheap.DocCheapError`. When the API
|
|
107
|
+
answers with an error status, it is an `APIError` carrying the HTTP status, the
|
|
108
|
+
API's error code and its message, narrowed to a subclass you can catch:
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
from doc_cheap import APIError, NotFoundError, RateLimitError
|
|
112
|
+
|
|
113
|
+
try:
|
|
114
|
+
scan = client.get_scan(scan_id)
|
|
115
|
+
except NotFoundError:
|
|
116
|
+
scan = None
|
|
117
|
+
except RateLimitError as err:
|
|
118
|
+
print("try again in", err.retry_after, "seconds")
|
|
119
|
+
except APIError as err:
|
|
120
|
+
print(err.status_code, err.code, err.message, err.request_id)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
| Exception | When |
|
|
124
|
+
| --- | --- |
|
|
125
|
+
| `InvalidRequestError` | The request was malformed or failed validation (400, 413, 415, 422). |
|
|
126
|
+
| `AuthenticationError` | The key is missing, unknown or revoked (401). |
|
|
127
|
+
| `PermissionDeniedError` | The key may not do this (403). |
|
|
128
|
+
| `InsufficientCreditsError` | The account has no credits left (402). |
|
|
129
|
+
| `NotFoundError` | No such scan (404). |
|
|
130
|
+
| `ConflictError` | An idempotency key is reused or still in progress (409). |
|
|
131
|
+
| `RateLimitError` | Too many requests; `retry_after` says how long to wait (429). |
|
|
132
|
+
| `ServiceUnavailableError` | The service is briefly unavailable (503). |
|
|
133
|
+
| `InternalServerError` | Any other server error (5xx). |
|
|
134
|
+
| `APIConnectionError` | No answer at all: a network failure or a timeout. |
|
|
135
|
+
|
|
136
|
+
An argument the API would refuse anyway – no image, an image over 25 MiB, a
|
|
137
|
+
reference over 128 characters – raises `InvalidArgumentError` (also a
|
|
138
|
+
`ValueError`) before any request is sent.
|
|
139
|
+
|
|
140
|
+
## Options
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
import httpx
|
|
144
|
+
from doc_cheap import Client
|
|
145
|
+
|
|
146
|
+
client = Client(
|
|
147
|
+
timeout=30.0,
|
|
148
|
+
user_agent="my-app/1.0",
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# Or bring your own httpx.Client for a proxy or a shared connection pool;
|
|
152
|
+
# the doc.cheap client leaves it open when it closes.
|
|
153
|
+
client = Client(http_client=httpx.Client(proxy="http://proxy.internal:3128"))
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
`base_url` (or the `DOC_CHEAP_API_BASE` environment variable) points the client
|
|
157
|
+
at another address, for example a test server.
|
|
158
|
+
|
|
159
|
+
## Resources
|
|
160
|
+
|
|
161
|
+
- [doc.cheap documentation](https://doc.cheap/docs)
|
|
162
|
+
- [Your first recognition](https://doc.cheap/docs/start/first-recognition)
|
|
163
|
+
- [From the sandbox to a live key](https://doc.cheap/docs/start/from-sandbox-to-live)
|
|
164
|
+
- [API reference](https://doc.cheap/docs/reference)
|
|
165
|
+
- [Handling errors](https://doc.cheap/docs/guides/handle-errors)
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# doc-cheap
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/doc-cheap/)
|
|
4
|
+
|
|
5
|
+
The Python client for [doc.cheap](https://doc.cheap): it sends a photo or scan
|
|
6
|
+
of a passport, national ID card or driving licence to the doc.cheap API and
|
|
7
|
+
returns the printed fields – name, date of birth, document number, expiry, the
|
|
8
|
+
machine-readable zone – as typed dictionaries.
|
|
9
|
+
|
|
10
|
+
One recognised document costs one credit, $0.01. Registering gives 100 free
|
|
11
|
+
documents every month. An unreadable image, an empty frame or an unsupported
|
|
12
|
+
document type costs nothing, and every answer says whether it was billed.
|
|
13
|
+
|
|
14
|
+
The package needs Python 3.10 or later and depends only on
|
|
15
|
+
[httpx](https://www.python-httpx.org/).
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
pip install doc-cheap
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick start
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from doc_cheap import SANDBOX_KEY, Client
|
|
27
|
+
|
|
28
|
+
with Client(SANDBOX_KEY) as client:
|
|
29
|
+
scan = client.recognize(path="passport.jpg")
|
|
30
|
+
|
|
31
|
+
print("status:", scan["meta"]["status"], "billed:", scan["meta"]["billed"])
|
|
32
|
+
if scan["holder"] and scan["holder"]["full_name"]:
|
|
33
|
+
print("holder:", scan["holder"]["full_name"])
|
|
34
|
+
if scan["document"] and scan["document"]["expiry_date"]:
|
|
35
|
+
print("expires:", scan["document"]["expiry_date"])
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## API keys
|
|
39
|
+
|
|
40
|
+
- **Live key** – `sk_live_…`, created in the
|
|
41
|
+
[doc.cheap cabinet](https://doc.cheap/docs/concepts/api-keys-and-sessions).
|
|
42
|
+
- **Sandbox key** – `sk_sandbox_public` (the `doc_cheap.SANDBOX_KEY` constant)
|
|
43
|
+
works without an account. It gives 10 free recognised documents per address
|
|
44
|
+
in all, and at most 10 requests per address an hour, whatever their answer.
|
|
45
|
+
|
|
46
|
+
`Client()` without a key reads it from the `DOC_CHEAP_API_KEY` environment
|
|
47
|
+
variable, which keeps a live key out of source code. The key is sent as a
|
|
48
|
+
Bearer token.
|
|
49
|
+
|
|
50
|
+
## Methods
|
|
51
|
+
|
|
52
|
+
| Method | Request | What it does |
|
|
53
|
+
| --- | --- | --- |
|
|
54
|
+
| `recognize` | `POST /v1/scans` | Reads one JPEG or PNG image, from a file (`path`), raw bytes (`image`) or base64 (`image_base64`), with an optional `reference` label, `idempotency_key`, `expect_country`, `return_portrait` and `retain_hours`. |
|
|
55
|
+
| `get_scan` | `GET /v1/scans/{id}` | Returns a stored result. |
|
|
56
|
+
| `list_scans` | `GET /v1/scans` | Returns one page of stored results; pass `next_cursor` back as `cursor` for the next page. |
|
|
57
|
+
| `delete_scan` | `DELETE /v1/scans/{id}` | Deletes a stored result. |
|
|
58
|
+
| `usage` | `GET /v1/usage` | Returns this month's free credits, the paid credits, the credits spent and the scan counters. |
|
|
59
|
+
|
|
60
|
+
An image that holds no readable document is not an error: the scan comes back
|
|
61
|
+
with a status such as `unreadable` or `no_document_found` and `billed` set to
|
|
62
|
+
`False`.
|
|
63
|
+
|
|
64
|
+
**Stored results.** A result is stored only when the scan was made with a live
|
|
65
|
+
key under a non-zero retention window, and only until that window ends. Under
|
|
66
|
+
the sandbox key nothing is stored, so `get_scan` and `delete_scan` raise
|
|
67
|
+
`NotFoundError`. None of `get_scan`, `delete_scan` or `usage` charges a credit.
|
|
68
|
+
|
|
69
|
+
## Errors
|
|
70
|
+
|
|
71
|
+
Every exception the package raises is a `doc_cheap.DocCheapError`. When the API
|
|
72
|
+
answers with an error status, it is an `APIError` carrying the HTTP status, the
|
|
73
|
+
API's error code and its message, narrowed to a subclass you can catch:
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
from doc_cheap import APIError, NotFoundError, RateLimitError
|
|
77
|
+
|
|
78
|
+
try:
|
|
79
|
+
scan = client.get_scan(scan_id)
|
|
80
|
+
except NotFoundError:
|
|
81
|
+
scan = None
|
|
82
|
+
except RateLimitError as err:
|
|
83
|
+
print("try again in", err.retry_after, "seconds")
|
|
84
|
+
except APIError as err:
|
|
85
|
+
print(err.status_code, err.code, err.message, err.request_id)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
| Exception | When |
|
|
89
|
+
| --- | --- |
|
|
90
|
+
| `InvalidRequestError` | The request was malformed or failed validation (400, 413, 415, 422). |
|
|
91
|
+
| `AuthenticationError` | The key is missing, unknown or revoked (401). |
|
|
92
|
+
| `PermissionDeniedError` | The key may not do this (403). |
|
|
93
|
+
| `InsufficientCreditsError` | The account has no credits left (402). |
|
|
94
|
+
| `NotFoundError` | No such scan (404). |
|
|
95
|
+
| `ConflictError` | An idempotency key is reused or still in progress (409). |
|
|
96
|
+
| `RateLimitError` | Too many requests; `retry_after` says how long to wait (429). |
|
|
97
|
+
| `ServiceUnavailableError` | The service is briefly unavailable (503). |
|
|
98
|
+
| `InternalServerError` | Any other server error (5xx). |
|
|
99
|
+
| `APIConnectionError` | No answer at all: a network failure or a timeout. |
|
|
100
|
+
|
|
101
|
+
An argument the API would refuse anyway – no image, an image over 25 MiB, a
|
|
102
|
+
reference over 128 characters – raises `InvalidArgumentError` (also a
|
|
103
|
+
`ValueError`) before any request is sent.
|
|
104
|
+
|
|
105
|
+
## Options
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
import httpx
|
|
109
|
+
from doc_cheap import Client
|
|
110
|
+
|
|
111
|
+
client = Client(
|
|
112
|
+
timeout=30.0,
|
|
113
|
+
user_agent="my-app/1.0",
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# Or bring your own httpx.Client for a proxy or a shared connection pool;
|
|
117
|
+
# the doc.cheap client leaves it open when it closes.
|
|
118
|
+
client = Client(http_client=httpx.Client(proxy="http://proxy.internal:3128"))
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`base_url` (or the `DOC_CHEAP_API_BASE` environment variable) points the client
|
|
122
|
+
at another address, for example a test server.
|
|
123
|
+
|
|
124
|
+
## Resources
|
|
125
|
+
|
|
126
|
+
- [doc.cheap documentation](https://doc.cheap/docs)
|
|
127
|
+
- [Your first recognition](https://doc.cheap/docs/start/first-recognition)
|
|
128
|
+
- [From the sandbox to a live key](https://doc.cheap/docs/start/from-sandbox-to-live)
|
|
129
|
+
- [API reference](https://doc.cheap/docs/reference)
|
|
130
|
+
- [Handling errors](https://doc.cheap/docs/guides/handle-errors)
|
|
131
|
+
|
|
132
|
+
## License
|
|
133
|
+
|
|
134
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.25"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "doc-cheap"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Typed Python client for the doc.cheap document-recognition API: read passports, ID cards and driver's licences into JSON."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
requires-python = ">=3.10"
|
|
13
|
+
authors = [{ name = "Teoh Chin Heng", email = "admin@doc.cheap" }]
|
|
14
|
+
keywords = ["ocr", "passport", "id-card", "mrz", "document-recognition", "kyc", "doc.cheap"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Operating System :: OS Independent",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
25
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
26
|
+
"Typing :: Typed",
|
|
27
|
+
]
|
|
28
|
+
dependencies = ["httpx>=0.27,<1"]
|
|
29
|
+
|
|
30
|
+
[project.optional-dependencies]
|
|
31
|
+
test = ["pytest>=8", "pytest-cov>=5"]
|
|
32
|
+
dev = ["pytest>=8", "pytest-cov>=5", "ruff>=0.6", "mypy>=1.11"]
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://doc.cheap"
|
|
36
|
+
Documentation = "https://doc.cheap/docs"
|
|
37
|
+
Source = "https://gitlab.com/doccheap/doc-cheap-python"
|
|
38
|
+
Changelog = "https://gitlab.com/doccheap/doc-cheap-python/-/blob/main/CHANGELOG.md"
|
|
39
|
+
|
|
40
|
+
[tool.hatch.build.targets.wheel]
|
|
41
|
+
packages = ["src/doc_cheap"]
|
|
42
|
+
|
|
43
|
+
[tool.hatch.build.targets.sdist]
|
|
44
|
+
include = ["src/doc_cheap", "tests", "README.md", "CHANGELOG.md", "LICENSE", "pyproject.toml"]
|
|
45
|
+
|
|
46
|
+
[tool.pytest.ini_options]
|
|
47
|
+
testpaths = ["tests"]
|
|
48
|
+
addopts = "-q"
|
|
49
|
+
|
|
50
|
+
[tool.coverage.run]
|
|
51
|
+
branch = true
|
|
52
|
+
source = ["doc_cheap"]
|
|
53
|
+
|
|
54
|
+
[tool.coverage.report]
|
|
55
|
+
fail_under = 100
|
|
56
|
+
show_missing = true
|
|
57
|
+
|
|
58
|
+
[tool.ruff]
|
|
59
|
+
line-length = 100
|
|
60
|
+
target-version = "py310"
|
|
61
|
+
|
|
62
|
+
[tool.ruff.lint]
|
|
63
|
+
select = ["E", "F", "W", "I", "B", "UP", "SIM", "RUF"]
|
|
64
|
+
|
|
65
|
+
[tool.mypy]
|
|
66
|
+
strict = true
|
|
67
|
+
python_version = "3.10"
|
|
68
|
+
files = ["src", "tests"]
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""A typed Python client for the doc.cheap document-recognition API.
|
|
2
|
+
|
|
3
|
+
>>> from doc_cheap import Client, SANDBOX_KEY
|
|
4
|
+
>>> with Client(SANDBOX_KEY) as client: # doctest: +SKIP
|
|
5
|
+
... scan = client.recognize(path="passport.jpg")
|
|
6
|
+
... print(scan["meta"]["status"], scan["holder"])
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from ._client import (
|
|
10
|
+
API_KEY_ENV,
|
|
11
|
+
BASE_URL_ENV,
|
|
12
|
+
DEFAULT_BASE_URL,
|
|
13
|
+
MAX_IMAGE_BYTES,
|
|
14
|
+
SANDBOX_KEY,
|
|
15
|
+
Client,
|
|
16
|
+
)
|
|
17
|
+
from ._errors import (
|
|
18
|
+
APIConnectionError,
|
|
19
|
+
APIError,
|
|
20
|
+
AuthenticationError,
|
|
21
|
+
ConflictError,
|
|
22
|
+
DocCheapError,
|
|
23
|
+
InsufficientCreditsError,
|
|
24
|
+
InternalServerError,
|
|
25
|
+
InvalidArgumentError,
|
|
26
|
+
InvalidRequestError,
|
|
27
|
+
NotFoundError,
|
|
28
|
+
PermissionDeniedError,
|
|
29
|
+
RateLimitError,
|
|
30
|
+
ServiceUnavailableError,
|
|
31
|
+
)
|
|
32
|
+
from ._types import (
|
|
33
|
+
Confidence,
|
|
34
|
+
CreditsByKind,
|
|
35
|
+
FreeAllowance,
|
|
36
|
+
Scan,
|
|
37
|
+
ScanAuthenticity,
|
|
38
|
+
ScanCheck,
|
|
39
|
+
ScanDeletion,
|
|
40
|
+
ScanDocument,
|
|
41
|
+
ScanField,
|
|
42
|
+
ScanHolder,
|
|
43
|
+
ScanImages,
|
|
44
|
+
ScanList,
|
|
45
|
+
ScanMeta,
|
|
46
|
+
ScanMRZ,
|
|
47
|
+
ScanQuality,
|
|
48
|
+
ScanSummary,
|
|
49
|
+
ScanTiming,
|
|
50
|
+
Status,
|
|
51
|
+
Usage,
|
|
52
|
+
UsagePeriod,
|
|
53
|
+
UsageScans,
|
|
54
|
+
)
|
|
55
|
+
from ._version import __version__
|
|
56
|
+
|
|
57
|
+
__all__ = [
|
|
58
|
+
"API_KEY_ENV",
|
|
59
|
+
"BASE_URL_ENV",
|
|
60
|
+
"DEFAULT_BASE_URL",
|
|
61
|
+
"MAX_IMAGE_BYTES",
|
|
62
|
+
"SANDBOX_KEY",
|
|
63
|
+
"APIConnectionError",
|
|
64
|
+
"APIError",
|
|
65
|
+
"AuthenticationError",
|
|
66
|
+
"Client",
|
|
67
|
+
"Confidence",
|
|
68
|
+
"ConflictError",
|
|
69
|
+
"CreditsByKind",
|
|
70
|
+
"DocCheapError",
|
|
71
|
+
"FreeAllowance",
|
|
72
|
+
"InsufficientCreditsError",
|
|
73
|
+
"InternalServerError",
|
|
74
|
+
"InvalidArgumentError",
|
|
75
|
+
"InvalidRequestError",
|
|
76
|
+
"NotFoundError",
|
|
77
|
+
"PermissionDeniedError",
|
|
78
|
+
"RateLimitError",
|
|
79
|
+
"Scan",
|
|
80
|
+
"ScanAuthenticity",
|
|
81
|
+
"ScanCheck",
|
|
82
|
+
"ScanDeletion",
|
|
83
|
+
"ScanDocument",
|
|
84
|
+
"ScanField",
|
|
85
|
+
"ScanHolder",
|
|
86
|
+
"ScanImages",
|
|
87
|
+
"ScanList",
|
|
88
|
+
"ScanMRZ",
|
|
89
|
+
"ScanMeta",
|
|
90
|
+
"ScanQuality",
|
|
91
|
+
"ScanSummary",
|
|
92
|
+
"ScanTiming",
|
|
93
|
+
"ServiceUnavailableError",
|
|
94
|
+
"Status",
|
|
95
|
+
"Usage",
|
|
96
|
+
"UsagePeriod",
|
|
97
|
+
"UsageScans",
|
|
98
|
+
"__version__",
|
|
99
|
+
]
|