Skip to content

Commit 0e4c366

Browse files
✨ add support for custom httpx client for V1 and V2
1 parent 8487692 commit 0e4c366

8 files changed

Lines changed: 126 additions & 39 deletions

File tree

mindee/input/url_input_source.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,14 @@ def __fill_filename(self, filename=None) -> str:
173173
return filename
174174

175175
@staticmethod
176-
def __make_request(url, auth, headers, redirects, max_redirects) -> bytes:
176+
def __make_request(
177+
url,
178+
auth,
179+
headers,
180+
redirects,
181+
max_redirects,
182+
http_client: httpx.Client | None = None,
183+
) -> bytes:
177184
"""
178185
Makes an HTTP request to the given URL, while following redirections.
179186
@@ -185,11 +192,15 @@ def __make_request(url, auth, headers, redirects, max_redirects) -> bytes:
185192
:return: The content of the response.
186193
:raises MindeeSourceError: If max redirects are exceeded or the request fails.
187194
"""
188-
result = httpx.get(url, headers=headers, timeout=120, auth=auth)
195+
http_client = http_client or httpx.Client()
196+
result = http_client.get(
197+
url, headers=headers, timeout=120, auth=auth, follow_redirects=True
198+
)
189199
if 299 < result.status_code < 400:
190200
if redirects == max_redirects:
191201
raise MindeeSourceError(
192-
f"Can't reach URL after {redirects} out of {max_redirects} redirects, "
202+
f"Can't reach URL after {redirects} out of {max_redirects} "
203+
f"redirects, "
193204
f"aborting operation."
194205
)
195206
return URLInputSource.__make_request(

mindee/v1/client.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from time import sleep
22

3+
import httpx
4+
35
from mindee.client_mixin import ClientMixin
46
from mindee.error.mindee_error import MindeeClientError, MindeeError
57
from mindee.error.mindee_http_error import handle_error
@@ -59,14 +61,21 @@ class Client(ClientMixin):
5961
"""
6062

6163
api_key: str
64+
"""API key for all endpoints."""
65+
http_client: httpx.Client
66+
"""HTTP client for making requests."""
6267

63-
def __init__(self, api_key: str = "") -> None:
68+
def __init__(
69+
self, api_key: str = "", http_client: httpx.Client | None = None
70+
) -> None:
6471
"""
6572
Mindee API Client.
6673
6774
:param api_key: Your API key for all endpoints
75+
:param http_client: HTTP client for making requests.
6876
"""
6977
self.api_key = api_key
78+
self.http_client = http_client or httpx.Client()
7079

7180
def parse(
7281
self,
@@ -522,7 +531,8 @@ def _send_to_workflow(
522531
raise MindeeClientError("No input document provided")
523532

524533
workflow_endpoint = WorkflowEndpoint(
525-
WorkflowSettings(api_key=self.api_key, workflow_id=workflow_id)
534+
WorkflowSettings(api_key=self.api_key, workflow_id=workflow_id),
535+
self.http_client,
526536
)
527537

528538
response = workflow_endpoint.workflow_execution_post(input_source, options)
@@ -555,8 +565,12 @@ def _build_endpoint(
555565
version=version,
556566
)
557567
if account_name and len(account_name) > 0 and account_name != "mindee":
558-
return CustomEndpoint(endpoint_name, account_name, version, api_settings)
559-
return Endpoint(endpoint_name, account_name, version, api_settings)
568+
return CustomEndpoint(
569+
endpoint_name, account_name, version, api_settings, self.http_client
570+
)
571+
return Endpoint(
572+
endpoint_name, account_name, version, api_settings, self.http_client
573+
)
560574

561575
def create_endpoint(
562576
self,
Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
1+
import httpx
2+
13
from mindee.v1.mindee_http.base_settings import BaseSettings
24

35

46
class BaseEndpoint:
57
"""Base endpoint class for the Mindee API."""
68

7-
def __init__(self, settings: BaseSettings) -> None:
9+
settings: BaseSettings
10+
http_client: httpx.Client
11+
12+
def __init__(
13+
self, settings: BaseSettings, http_client: httpx.Client | None = None
14+
) -> None:
815
"""
916
Base API endpoint class for all endpoints.
1017
1118
:param settings: Settings relating to all endpoints.
19+
:param http_client: HTTP client for making requests.
1220
"""
1321
self.settings = settings
22+
self.http_client = http_client or httpx.Client()

mindee/v1/mindee_http/endpoint.py

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,23 @@ class Endpoint(BaseEndpoint):
1313
settings: MindeeAPI
1414

1515
def __init__(
16-
self, url_name: str, owner: str, version: str, settings: MindeeAPI
16+
self,
17+
url_name: str,
18+
owner: str,
19+
version: str,
20+
settings: MindeeAPI,
21+
http_client: httpx.Client | None = None,
1722
) -> None:
1823
"""
1924
Generic API endpoint for a product.
2025
2126
:param owner: owner of the product
2227
:param url_name: name of the product as it appears in the URL
2328
:param version: interface version
29+
:param settings: settings for the API
30+
:param http_client: HTTP client for making requests.
2431
"""
25-
super().__init__(settings)
32+
super().__init__(settings, http_client)
2633
self.owner = owner
2734
self.url_name = url_name
2835
self.version = version
@@ -42,7 +49,8 @@ def predict_req_post(
4249
:param include_words: Include raw OCR words in the response
4350
:param close_file: Whether to `close()` the file after parsing it.
4451
:param cropper: Including Mindee cropping results.
45-
:param full_text: Whether to include the full OCR text response in compatible APIs.
52+
:param full_text: Whether to include the full OCR text response in compatible
53+
APIs.
4654
:return: httpx response
4755
"""
4856
return self._custom_request(
@@ -66,7 +74,8 @@ def predict_async_req_post(
6674
:param include_words: Include raw OCR words in the response
6775
:param close_file: Whether to `close()` the file after parsing it.
6876
:param cropper: Including Mindee cropping results.
69-
:param full_text: Whether to include the full OCR text response in compatible APIs.
77+
:param full_text: Whether to include the full OCR text response in compatible
78+
APIs.
7079
:param workflow_id: Workflow ID.
7180
:param rag: If set, will enable Retrieval-Augmented Generation.
7281
:return: httpx response
@@ -112,7 +121,7 @@ def _custom_request(
112121

113122
if isinstance(input_source, URLInputSource):
114123
data["document"] = input_source.url
115-
response = httpx.post(
124+
response = self.http_client.post(
116125
url=url,
117126
headers=self.settings.base_headers,
118127
data=data,
@@ -121,7 +130,7 @@ def _custom_request(
121130
)
122131
else:
123132
files = {"document": input_source.read_contents(close_file)}
124-
response = httpx.post(
133+
response = self.http_client.post(
125134
url=url,
126135
files=files,
127136
headers=self.settings.base_headers,
@@ -138,7 +147,7 @@ def document_queue_req_get(self, queue_id: str) -> httpx.Response:
138147
139148
:param queue_id: queue_id received from the API
140149
"""
141-
return httpx.get(
150+
return self.http_client.get(
142151
f"{self.settings.url_root}/documents/queue/{queue_id}",
143152
headers=self.settings.base_headers,
144153
timeout=self.settings.request_timeout,
@@ -147,7 +156,7 @@ def document_queue_req_get(self, queue_id: str) -> httpx.Response:
147156

148157
def openapi_get_req(self) -> httpx.Response:
149158
"""Get the OpenAPI specification of the product."""
150-
return httpx.get(
159+
return self.http_client.get(
151160
f"{self.settings.url_root}/openapi.json",
152161
headers=self.settings.base_headers,
153162
timeout=self.settings.request_timeout,
@@ -163,7 +172,7 @@ def document_feedback_req_put(
163172
:param document_id: ID of the document to send feedback to.
164173
:param feedback: Feedback object to send.
165174
"""
166-
return httpx.put(
175+
return self.http_client.put(
167176
f"{self.settings.base_url}/v1/documents/{document_id}/feedback",
168177
headers=self.settings.base_headers,
169178
data=feedback,
@@ -187,7 +196,7 @@ def training_req_post(
187196
files = {"document": input_source.read_contents(close_file)}
188197
params = {"training": True, "with_candidates": True}
189198

190-
response = httpx.post(
199+
response = self.http_client.post(
191200
f"{self.settings.url_root}/predict",
192201
files=files,
193202
headers=self.settings.base_headers,
@@ -209,7 +218,7 @@ def training_async_req_post(
209218
files = {"document": input_source.read_contents(close_file)}
210219
params = {"training": True, "async": True}
211220

212-
response = httpx.post(
221+
response = self.http_client.post(
213222
f"{self.settings.url_root}/predict",
214223
files=files,
215224
headers=self.settings.base_headers,
@@ -240,7 +249,7 @@ def documents_req_get(self, page_id: int = 1) -> httpx.Response:
240249
params = {
241250
"page": page_id,
242251
}
243-
response = httpx.get(
252+
response = self.http_client.get(
244253
f"{self.settings.url_root}/documents",
245254
headers=self.settings.base_headers,
246255
params=params,
@@ -260,7 +269,7 @@ def document_req_get(self, document_id: str) -> httpx.Response:
260269
"include_candidates": True,
261270
"global_orientation": True,
262271
}
263-
response = httpx.get(
272+
response = self.http_client.get(
264273
f"{self.settings.url_root}/documents/{document_id}",
265274
headers=self.settings.base_headers,
266275
params=params,
@@ -279,7 +288,7 @@ def annotations_req_post(
279288
:param annotations: Annotations object
280289
:return: httpx response
281290
"""
282-
response = httpx.post(
291+
response = self.http_client.post(
283292
f"{self.settings.url_root}/documents/{document_id}/annotations",
284293
headers=self.settings.base_headers,
285294
json=annotations,
@@ -297,7 +306,7 @@ def annotations_req_put(
297306
:param annotations: Annotations object
298307
:return: httpx response
299308
"""
300-
response = httpx.put(
309+
response = self.http_client.put(
301310
f"{self.settings.url_root}/documents/{document_id}/annotations",
302311
headers=self.settings.base_headers,
303312
json=annotations,
@@ -312,7 +321,7 @@ def annotations_req_del(self, document_id: str) -> httpx.Response:
312321
:param document_id: ID of the document to annotate
313322
:return: httpx response
314323
"""
315-
response = httpx.delete(
324+
response = self.http_client.delete(
316325
f"{self.settings.url_root}/documents/{document_id}/annotations",
317326
headers=self.settings.base_headers,
318327
timeout=self.settings.request_timeout,

mindee/v1/mindee_http/workflow_endpoint.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,17 @@ class WorkflowEndpoint(BaseEndpoint):
1111
"""Workflow endpoint."""
1212

1313
settings: WorkflowSettings
14+
"""Settings object."""
1415

15-
def __init__(self, settings: WorkflowSettings) -> None:
16+
def __init__(
17+
self, settings: WorkflowSettings, http_client: httpx.Client | None = None
18+
) -> None:
1619
"""
1720
Workflow Endpoint.
1821
1922
:param settings: Settings object.
2023
"""
21-
super().__init__(settings)
24+
super().__init__(settings, http_client)
2225

2326
def workflow_execution_post(
2427
self,
@@ -50,7 +53,7 @@ def workflow_execution_post(
5053

5154
if isinstance(input_source, URLInputSource):
5255
data["document"] = input_source.url
53-
response = httpx.post(
56+
response = self.http_client.post(
5457
self.settings.url_root,
5558
headers=self.settings.base_headers,
5659
data=data,
@@ -59,7 +62,7 @@ def workflow_execution_post(
5962
)
6063
else:
6164
files = {"document": input_source.read_contents(True)}
62-
response = httpx.post(
65+
response = self.http_client.post(
6366
self.settings.url_root,
6467
files=files,
6568
headers=self.settings.base_headers,

mindee/v2/client.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from time import sleep
22
from typing import TypeVar
33

4+
import httpx
5+
46
from mindee.client_mixin import ClientMixin
57
from mindee.client_options.polling_options import PollingOptions
68
from mindee.error.mindee_error import MindeeError
@@ -27,14 +29,16 @@ class Client(ClientMixin):
2729
api_key: str | None
2830
mindee_api: MindeeAPIV2
2931

30-
def __init__(self, api_key: str | None = None) -> None:
32+
def __init__(
33+
self, api_key: str | None = None, http_client: httpx.Client | None = None
34+
) -> None:
3135
"""
3236
Mindee API Client.
3337
3438
:param api_key: Your API key for all endpoints
3539
"""
3640
self.api_key = api_key
37-
self.mindee_api = MindeeAPIV2(api_key)
41+
self.mindee_api = MindeeAPIV2(api_key, http_client)
3842

3943
def enqueue(
4044
self,

0 commit comments

Comments
 (0)