Skip to content

Commit 84d68ea

Browse files
✨ add support for custom httpx client for V1 and V2 (#415)
1 parent efa7a7b commit 84d68ea

72 files changed

Lines changed: 594 additions & 241 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎mindee/error/mindee_http_error.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from mindee.error.mindee_error import MindeeError
2-
from mindee.parsing.common import StringDict
2+
from mindee.parsing.common.string_dict import StringDict
33

44

55
class MindeeHTTPError(RuntimeError):

‎mindee/input/url_input_source.py‎

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from mindee.error.mindee_error import MindeeSourceError
1111
from mindee.input.bytes_input import BytesInput
1212
from mindee.logger import logger
13+
from mindee.parsing.common.string_dict import StringDict
1314

1415

1516
class URLInputSource:
@@ -173,7 +174,14 @@ def __fill_filename(self, filename=None) -> str:
173174
return filename
174175

175176
@staticmethod
176-
def __make_request(url, auth, headers, redirects, max_redirects) -> bytes:
177+
def __make_request(
178+
url,
179+
auth,
180+
headers,
181+
redirects,
182+
max_redirects,
183+
http_client: httpx.Client | None = None,
184+
) -> bytes:
177185
"""
178186
Makes an HTTP request to the given URL, while following redirections.
179187
@@ -185,20 +193,36 @@ def __make_request(url, auth, headers, redirects, max_redirects) -> bytes:
185193
:return: The content of the response.
186194
:raises MindeeSourceError: If max redirects are exceeded or the request fails.
187195
"""
188-
result = httpx.get(url, headers=headers, timeout=120, auth=auth)
196+
get_kwargs: StringDict = {
197+
"headers": headers,
198+
"timeout": 120,
199+
"auth": auth,
200+
"follow_redirects": True,
201+
}
202+
if http_client is None:
203+
result = httpx.get(url, **get_kwargs)
204+
else:
205+
result = http_client.get(url, **get_kwargs)
189206
if 299 < result.status_code < 400:
190207
if redirects == max_redirects:
191208
raise MindeeSourceError(
192-
f"Can't reach URL after {redirects} out of {max_redirects} redirects, "
209+
f"Can't reach URL after {redirects} out of {max_redirects} "
210+
f"redirects, "
193211
f"aborting operation."
194212
)
195213
return URLInputSource.__make_request(
196-
result.headers["Location"], auth, headers, redirects + 1, max_redirects
214+
result.headers["Location"],
215+
auth,
216+
headers,
217+
redirects + 1,
218+
max_redirects,
219+
http_client,
197220
)
198221

199222
if result.status_code >= 400 or result.status_code < 200:
200223
raise MindeeSourceError(
201224
f"Couldn't retrieve file from server, error code {result.status_code}."
202225
)
203-
226+
if http_client is not None and not http_client.is_closed:
227+
http_client.close()
204228
return result.content

‎mindee/mindee_http/response_validation.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import httpx
44

5-
from mindee.parsing.common import StringDict
5+
from mindee.parsing.common.string_dict import StringDict
66

77

88
def is_valid_sync_response(response: httpx.Response) -> bool:

‎mindee/mindee_http/settings_mixin.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ class SettingsMixin:
33

44
base_url: str
55
"""Base URL for all V2 requests."""
6-
request_timeout: int
6+
request_timeout: float
77
"""Timeout for all requests."""
88

99
def set_timeout(self, value: str | int) -> None:

‎mindee/v1/client.py‎

Lines changed: 35 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 | None
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
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,
@@ -583,3 +597,20 @@ def create_endpoint(
583597
)
584598
version = "1"
585599
return self._build_endpoint(endpoint_name, account_name, version)
600+
601+
def close(self):
602+
"""Close the HTTP client."""
603+
if self.http_client and not self.http_client.is_closed:
604+
self.http_client.close()
605+
606+
def __enter__(self):
607+
return self
608+
609+
def __exit__(self, exc_type, exc_val, exc_tb):
610+
self.close()
611+
612+
def __del__(self):
613+
"""Ensure the HTTP client is closed when the object is garbage collected."""
614+
if self.http_client and self.http_client and not self.http_client.is_closed:
615+
logger.info("Force-closing unclosed Mindee Client (V1) %s.", str(self))
616+
self.close()
Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
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+
"""Settings relating to all endpoints."""
11+
http_client: httpx.Client | None
12+
"""HTTP client for making requests."""
13+
14+
def __init__(
15+
self, settings: BaseSettings, http_client: httpx.Client | None = None
16+
) -> None:
817
"""
918
Base API endpoint class for all endpoints.
1019
1120
:param settings: Settings relating to all endpoints.
21+
:param http_client: HTTP client for making requests.
1222
"""
1323
self.settings = settings
24+
self.http_client = http_client

0 commit comments

Comments
 (0)