Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion mindee/error/mindee_http_error.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from mindee.error.mindee_error import MindeeError
from mindee.parsing.common import StringDict
from mindee.parsing.common.string_dict import StringDict


class MindeeHTTPError(RuntimeError):
Expand Down
34 changes: 29 additions & 5 deletions mindee/input/url_input_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from mindee.error.mindee_error import MindeeSourceError
from mindee.input.bytes_input import BytesInput
from mindee.logger import logger
from mindee.parsing.common.string_dict import StringDict


class URLInputSource:
Expand Down Expand Up @@ -173,7 +174,14 @@ def __fill_filename(self, filename=None) -> str:
return filename

@staticmethod
def __make_request(url, auth, headers, redirects, max_redirects) -> bytes:
def __make_request(
url,
auth,
headers,
redirects,
max_redirects,
http_client: httpx.Client | None = None,
) -> bytes:
"""
Makes an HTTP request to the given URL, while following redirections.

Expand All @@ -185,20 +193,36 @@ def __make_request(url, auth, headers, redirects, max_redirects) -> bytes:
:return: The content of the response.
:raises MindeeSourceError: If max redirects are exceeded or the request fails.
"""
result = httpx.get(url, headers=headers, timeout=120, auth=auth)
get_kwargs: StringDict = {
"headers": headers,
"timeout": 120,
"auth": auth,
"follow_redirects": True,
}
if http_client is None:
result = httpx.get(url, **get_kwargs)
else:
result = http_client.get(url, **get_kwargs)
if 299 < result.status_code < 400:
if redirects == max_redirects:
raise MindeeSourceError(
f"Can't reach URL after {redirects} out of {max_redirects} redirects, "
f"Can't reach URL after {redirects} out of {max_redirects} "
f"redirects, "
f"aborting operation."
)
return URLInputSource.__make_request(
result.headers["Location"], auth, headers, redirects + 1, max_redirects
result.headers["Location"],
auth,
headers,
redirects + 1,
max_redirects,
http_client,
)

if result.status_code >= 400 or result.status_code < 200:
raise MindeeSourceError(
f"Couldn't retrieve file from server, error code {result.status_code}."
)

if http_client is not None and not http_client.is_closed:
http_client.close()
return result.content
2 changes: 1 addition & 1 deletion mindee/mindee_http/response_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import httpx

from mindee.parsing.common import StringDict
from mindee.parsing.common.string_dict import StringDict


def is_valid_sync_response(response: httpx.Response) -> bool:
Expand Down
2 changes: 1 addition & 1 deletion mindee/mindee_http/settings_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ class SettingsMixin:

base_url: str
"""Base URL for all V2 requests."""
request_timeout: int
request_timeout: float
"""Timeout for all requests."""

def set_timeout(self, value: str | int) -> None:
Expand Down
39 changes: 35 additions & 4 deletions mindee/v1/client.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from time import sleep

import httpx

from mindee.client_mixin import ClientMixin
from mindee.error.mindee_error import MindeeClientError, MindeeError
from mindee.error.mindee_http_error import handle_error
Expand Down Expand Up @@ -59,14 +61,21 @@ class Client(ClientMixin):
"""

api_key: str
"""API key for all endpoints."""
http_client: httpx.Client | None
"""HTTP client for making requests."""

def __init__(self, api_key: str = "") -> None:
def __init__(
self, api_key: str = "", http_client: httpx.Client | None = None
) -> None:
"""
Mindee API Client.

:param api_key: Your API key for all endpoints
:param http_client: HTTP client for making requests.
"""
self.api_key = api_key
self.http_client = http_client

def parse(
self,
Expand Down Expand Up @@ -522,7 +531,8 @@ def _send_to_workflow(
raise MindeeClientError("No input document provided")

workflow_endpoint = WorkflowEndpoint(
WorkflowSettings(api_key=self.api_key, workflow_id=workflow_id)
WorkflowSettings(api_key=self.api_key, workflow_id=workflow_id),
self.http_client,
)

response = workflow_endpoint.workflow_execution_post(input_source, options)
Expand Down Expand Up @@ -555,8 +565,12 @@ def _build_endpoint(
version=version,
)
if account_name and len(account_name) > 0 and account_name != "mindee":
return CustomEndpoint(endpoint_name, account_name, version, api_settings)
return Endpoint(endpoint_name, account_name, version, api_settings)
return CustomEndpoint(
endpoint_name, account_name, version, api_settings, self.http_client
)
return Endpoint(
endpoint_name, account_name, version, api_settings, self.http_client
)

def create_endpoint(
self,
Expand All @@ -583,3 +597,20 @@ def create_endpoint(
)
version = "1"
return self._build_endpoint(endpoint_name, account_name, version)

def close(self):
"""Close the HTTP client."""
if self.http_client and not self.http_client.is_closed:
self.http_client.close()

def __enter__(self):
return self

def __exit__(self, exc_type, exc_val, exc_tb):
self.close()

def __del__(self):
"""Ensure the HTTP client is closed when the object is garbage collected."""
if self.http_client and self.http_client and not self.http_client.is_closed:
logger.info("Force-closing unclosed Mindee Client (V1) %s.", str(self))
self.close()
13 changes: 12 additions & 1 deletion mindee/v1/mindee_http/base_endpoint.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
import httpx

from mindee.v1.mindee_http.base_settings import BaseSettings


class BaseEndpoint:
"""Base endpoint class for the Mindee API."""

def __init__(self, settings: BaseSettings) -> None:
settings: BaseSettings
"""Settings relating to all endpoints."""
http_client: httpx.Client | None
"""HTTP client for making requests."""

def __init__(
self, settings: BaseSettings, http_client: httpx.Client | None = None
) -> None:
"""
Base API endpoint class for all endpoints.

:param settings: Settings relating to all endpoints.
:param http_client: HTTP client for making requests.
"""
self.settings = settings
self.http_client = http_client
Loading
Loading