Skip to content

Commit ec198d1

Browse files
⬆️ update error mgmt (#181)
1 parent 26c827c commit ec198d1

File tree

12 files changed

+99
-72
lines changed

12 files changed

+99
-72
lines changed

mindee/cli.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from mindee import product
77
from mindee.client import Client, Endpoint
8+
from mindee.error.mindee_error import MindeeClientError
89
from mindee.input.page_options import PageOptions
910
from mindee.input.sources import LocalInputSource, UrlInputSource
1011
from mindee.parsing.common.async_predict_response import AsyncPredictResponse
@@ -188,7 +189,7 @@ def call_feedback(self) -> None:
188189
self.parsed_args.api_version,
189190
)
190191
if self.feedback is None:
191-
raise RuntimeError("Invalid feedback provided.")
192+
raise MindeeClientError("Invalid feedback provided.")
192193

193194
response: FeedbackResponse = self.client.send_feedback(
194195
self.document_info.doc_class,
@@ -222,7 +223,7 @@ def call_parse(self) -> None:
222223
print(response.raw_http)
223224
else:
224225
if response.document is None:
225-
raise RuntimeError("Something went wrong during async parsing.")
226+
raise MindeeClientError("Something went wrong during async parsing.")
226227
print(self._doc_str(self.parsed_args.output_type, response.document))
227228

228229
def _parse_sync(self) -> PredictResponse:
@@ -471,9 +472,9 @@ def _get_feedback_doc(self) -> StringDict:
471472
not self.parsed_args.feedback
472473
or not "feedback" in self.parsed_args.feedback
473474
):
474-
raise RuntimeError("Invalid feedback.")
475+
raise MindeeClientError("Invalid feedback.")
475476
if not json_doc or "feedback" not in json_doc:
476-
raise RuntimeError("Invalid feedback.")
477+
raise MindeeClientError("Invalid feedback.")
477478
return json_doc
478479

479480
def _set_input(self) -> None:

mindee/client.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from time import sleep
33
from typing import BinaryIO, Dict, Optional, Type, Union
44

5+
from mindee.error.mindee_error import MindeeClientError, MindeeError
6+
from mindee.error.mindee_http_error import handle_error
57
from mindee.input.page_options import PageOptions
68
from mindee.input.sources import (
79
Base64Input,
@@ -13,7 +15,6 @@
1315
)
1416
from mindee.logger import logger
1517
from mindee.mindee_http.endpoint import CustomEndpoint, Endpoint
16-
from mindee.mindee_http.error import handle_error
1718
from mindee.mindee_http.mindee_api import MindeeApi
1819
from mindee.parsing.common.async_predict_response import AsyncPredictResponse
1920
from mindee.parsing.common.feedback_response import FeedbackResponse
@@ -96,7 +97,7 @@ def parse(
9697
:param endpoint: For custom endpoints, an endpoint has to be given.
9798
"""
9899
if input_source is None:
99-
raise TypeError("No input document provided.")
100+
raise MindeeClientError("No input document provided.")
100101

101102
if not endpoint:
102103
endpoint = self._initialize_ots_endpoint(product_class)
@@ -148,7 +149,7 @@ def enqueue(
148149
:param endpoint: For custom endpoints, an endpoint has to be given.
149150
"""
150151
if input_source is None:
151-
raise TypeError("No input document provided.")
152+
raise MindeeClientError("No input document provided.")
152153

153154
if not endpoint:
154155
endpoint = self._initialize_ots_endpoint(product_class)
@@ -191,9 +192,13 @@ def _validate_async_params(
191192
self, initial_delay_sec: float, delay_sec: float
192193
) -> None:
193194
if delay_sec < 2:
194-
raise TypeError("Cannot set auto-parsing delay to less than 2 seconds.")
195+
raise MindeeClientError(
196+
"Cannot set auto-parsing delay to less than 2 seconds."
197+
)
195198
if initial_delay_sec < 4:
196-
raise TypeError("Cannot set initial parsing delay to less than 4 seconds.")
199+
raise MindeeClientError(
200+
"Cannot set initial parsing delay to less than 4 seconds."
201+
)
197202

198203
def enqueue_and_parse(
199204
self,
@@ -271,7 +276,7 @@ def enqueue_and_parse(
271276
)
272277

273278
if poll_results.job.status != "completed":
274-
raise RuntimeError(
279+
raise MindeeError(
275280
f"Couldn't retrieve document after {retry_counter} tries."
276281
)
277282

@@ -295,7 +300,7 @@ def send_feedback(
295300
:param endpoint: For custom endpoints, an endpoint has to be given.
296301
"""
297302
if not document_id or len(document_id) == 0:
298-
raise RuntimeError("Invalid document_id.")
303+
raise MindeeClientError("Invalid document_id.")
299304
if not endpoint:
300305
endpoint = self._initialize_ots_endpoint(product_class)
301306

@@ -348,7 +353,7 @@ def _predict_async(
348353
:param doc_config: Configuration of the document.
349354
"""
350355
if input_source is None:
351-
raise TypeError("No input document provided")
356+
raise MindeeClientError("No input document provided")
352357
if not endpoint:
353358
endpoint = self._initialize_ots_endpoint(product_class)
354359
response = endpoint.predict_async_req_post(
@@ -396,7 +401,7 @@ def _get_queued_document(
396401

397402
def _initialize_ots_endpoint(self, product_class: Type[Inference]) -> Endpoint:
398403
if product_class.__name__ == "CustomV1":
399-
raise TypeError("Missing endpoint specifications for custom build.")
404+
raise MindeeClientError("Missing endpoint specifications for custom build.")
400405
endpoint_info: Dict[str, str] = product_class.get_endpoint_info(product_class)
401406
return self._build_endpoint(
402407
endpoint_info["name"], OTS_OWNER, endpoint_info["version"]
@@ -432,7 +437,7 @@ def create_endpoint(
432437
Must inherit from ``mindee.product.base.Document``.
433438
"""
434439
if len(endpoint_name) == 0:
435-
raise TypeError("Custom endpoint require a valid 'endpoint_name'.")
440+
raise MindeeClientError("Custom endpoint require a valid 'endpoint_name'.")
436441
account_name = _clean_account_name(account_name)
437442
if not version or len(version) < 1:
438443
logger.debug(

mindee/error/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from mindee.error.mindee_error import MindeeClientError, MindeeError
2+
from mindee.error.mindee_http_error import (
3+
MindeeHTTPClientError,
4+
MindeeHTTPError,
5+
MindeeHTTPServerError,
6+
)

mindee/error/mindee_error.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
class MindeeError(RuntimeError):
2+
"""A generic exception relating to various client errors."""
3+
4+
5+
class MindeeClientError(MindeeError):
6+
"""An exception relating to document parsing."""
7+
8+
9+
class MindeeApiError(MindeeError):
10+
"""An exception relating to settings of the MindeeClient."""
11+
12+
13+
class MindeeSourceError(MindeeError):
14+
"""An exception relating to document loading."""

mindee/mindee_http/error.py renamed to mindee/error/mindee_http_error.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
from typing import Union
22

3+
from mindee.error.mindee_error import MindeeError
34
from mindee.parsing.common.string_dict import StringDict
45

56

6-
class MindeeHTTPException(RuntimeError):
7+
class MindeeHTTPError(RuntimeError):
78
"""An exception relating to HTTP calls."""
89

910
status_code: int
@@ -28,14 +29,6 @@ def __init__(self, http_error: StringDict, url: str, code: int) -> None:
2829
)
2930

3031

31-
class MindeeHTTPClientException(MindeeHTTPException):
32-
"""API Client HTTP exception."""
33-
34-
35-
class MindeeHTTPServerException(MindeeHTTPException):
36-
"""API Server HTTP exception."""
37-
38-
3932
def create_error_obj(response: Union[StringDict, str]) -> StringDict:
4033
"""
4134
Creates an error object based on a requests' payload.
@@ -46,7 +39,7 @@ def create_error_obj(response: Union[StringDict, str]) -> StringDict:
4639
if not isinstance(response, str):
4740
if "api_request" in response and "error" in response["api_request"]:
4841
return response["api_request"]["error"]
49-
raise RuntimeError(f"Could not build specific HTTP exception from '{response}'")
42+
raise MindeeError(f"Could not build specific HTTP exception from '{response}'")
5043
error_dict = {}
5144
if "Maximum pdf pages" in response:
5245
error_dict = {
@@ -87,7 +80,15 @@ def create_error_obj(response: Union[StringDict, str]) -> StringDict:
8780
return error_dict
8881

8982

90-
def handle_error(url: str, response: StringDict, code: int) -> MindeeHTTPException:
83+
class MindeeHTTPClientError(MindeeHTTPError):
84+
"""API Client HTTP exception."""
85+
86+
87+
class MindeeHTTPServerError(MindeeHTTPError):
88+
"""API Server HTTP exception."""
89+
90+
91+
def handle_error(url: str, response: StringDict, code: int) -> MindeeHTTPError:
9192
"""
9293
Creates an appropriate HTTP error exception, based on retrieved HTTP error code.
9394
@@ -96,7 +97,7 @@ def handle_error(url: str, response: StringDict, code: int) -> MindeeHTTPExcepti
9697
"""
9798
error_obj = create_error_obj(response)
9899
if 400 <= code <= 499:
99-
return MindeeHTTPClientException(error_obj, url, code)
100+
return MindeeHTTPClientError(error_obj, url, code)
100101
if 500 <= code <= 599:
101-
return MindeeHTTPServerException(error_obj, url, code)
102-
return MindeeHTTPException(error_obj, url, code)
102+
return MindeeHTTPServerError(error_obj, url, code)
103+
return MindeeHTTPError(error_obj, url, code)

mindee/input/sources.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import pikepdf
1010

11+
from mindee.error.mindee_error import MindeeSourceError
1112
from mindee.input.page_options import KEEP_ONLY, REMOVE
1213
from mindee.logger import logger
1314

@@ -90,7 +91,7 @@ def process_pdf(
9091
) -> None:
9192
"""Run any required processing on a PDF file."""
9293
if self.is_pdf_empty():
93-
raise AssertionError(f"PDF pages are empty in: {self.filename}")
94+
raise MindeeSourceError(f"PDF pages are empty in: {self.filename}")
9495
pages_count = self.count_doc_pages()
9596
if on_min_pages > pages_count:
9697
return
@@ -111,10 +112,10 @@ def process_pdf(
111112
logger.warning("Page index not in source document: %s", page_id)
112113
pages_to_keep = pages_to_remove.symmetric_difference(set(all_pages))
113114
else:
114-
raise AssertionError(f"Invalid cut behavior specified: {behavior}")
115+
raise MindeeSourceError(f"Invalid cut behavior specified: {behavior}")
115116

116117
if len(pages_to_keep) < 1:
117-
raise RuntimeError("Resulting PDF would have no pages left.")
118+
raise MindeeSourceError("Resulting PDF would have no pages left.")
118119
self.merge_pdf_pages(pages_to_keep)
119120

120121
def merge_pdf_pages(self, page_numbers: set) -> None:
@@ -260,7 +261,7 @@ def __init__(self, url: str) -> None:
260261
:param url: URL to send, must be HTTPS
261262
"""
262263
if not url.lower().startswith("https"):
263-
raise AssertionError("URL must be HTTPS")
264+
raise MindeeSourceError("URL must be HTTPS")
264265

265266
self.input_type = InputType.URL
266267

mindee/mindee_http/mindee_api.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from dataclasses import dataclass
33
from typing import Dict, Optional, Union
44

5+
from mindee.error.mindee_error import MindeeApiError
56
from mindee.logger import logger
67
from mindee.versions import __version__, get_platform, python_version
78

@@ -36,7 +37,7 @@ def __init__(
3637
):
3738
self._set_api_key(api_key)
3839
if not self.api_key or len(self.api_key) == 0:
39-
raise RuntimeError(
40+
raise MindeeApiError(
4041
(
4142
f"Missing API key for '{endpoint_name} v{version}' (belonging to {account_name}),"
4243
" check your Client configuration.\n"

mindee/parsing/common/inference.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from typing import Dict, Generic, List, Optional, TypeVar
22

3+
from mindee.error.mindee_error import MindeeError
34
from mindee.parsing.common.page import TypePage
45
from mindee.parsing.common.prediction import TypePrediction
56
from mindee.parsing.common.product import Product
@@ -62,7 +63,7 @@ def get_endpoint_info(klass) -> Dict[str, str]:
6263
"""
6364
if klass.endpoint_name and klass.endpoint_version:
6465
return {"name": klass.endpoint_name, "version": klass.endpoint_version}
65-
raise TypeError("Can't get endpoint information for {klass.__name__}")
66+
raise MindeeError("Can't get endpoint information for {klass.__name__}")
6667

6768

6869
TypeInference = TypeVar("TypeInference", bound=Inference)

tests/mindee_http/test_error.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
import pytest
55

66
from mindee import Client, product
7-
from mindee.input.sources import PathInput
8-
from mindee.mindee_http.error import (
9-
MindeeHTTPClientException,
10-
MindeeHTTPServerException,
7+
from mindee.error.mindee_http_error import (
8+
MindeeHTTPClientError,
9+
MindeeHTTPServerError,
1110
handle_error,
1211
)
12+
from mindee.input.sources import PathInput
1313
from tests.test_inputs import FILE_TYPES_DIR
1414
from tests.utils import clear_envvars, dummy_envvars
1515

@@ -36,32 +36,32 @@ def dummy_file(monkeypatch) -> PathInput:
3636

3737

3838
def test_http_client_error(dummy_client: Client, dummy_file: PathInput):
39-
with pytest.raises(MindeeHTTPClientException):
39+
with pytest.raises(MindeeHTTPClientError):
4040
dummy_client.parse(product.InvoiceV4, dummy_file)
4141

4242

4343
def test_http_enqueue_client_error(dummy_client: Client, dummy_file: PathInput):
44-
with pytest.raises(MindeeHTTPClientException):
44+
with pytest.raises(MindeeHTTPClientError):
4545
dummy_client.enqueue(product.InvoiceV4, dummy_file)
4646

4747

4848
def test_http_parse_client_error(dummy_client: Client, dummy_file: PathInput):
49-
with pytest.raises(MindeeHTTPClientException):
49+
with pytest.raises(MindeeHTTPClientError):
5050
dummy_client.parse_queued(product.InvoiceV4, "dummy-queue-id")
5151

5252

5353
def test_http_enqueue_and_parse_client_error(
5454
dummy_client: Client, dummy_file: PathInput
5555
):
56-
with pytest.raises(MindeeHTTPClientException):
56+
with pytest.raises(MindeeHTTPClientError):
5757
dummy_client.enqueue_and_parse(product.InvoiceV4, dummy_file)
5858

5959

6060
def test_http_400_error():
6161
error_ref = open(ERROR_DATA_DIR / "error_400_no_details.json")
6262
error_obj = json.load(error_ref)
6363
error_400 = handle_error("dummy-url", error_obj, 400)
64-
with pytest.raises(MindeeHTTPClientException):
64+
with pytest.raises(MindeeHTTPClientError):
6565
raise error_400
6666
assert error_400.status_code == 400
6767
assert error_400.api_code == "SomeCode"
@@ -73,7 +73,7 @@ def test_http_401_error():
7373
error_ref = open(ERROR_DATA_DIR / "error_401_invalid_token.json")
7474
error_obj = json.load(error_ref)
7575
error_401 = handle_error("dummy-url", error_obj, 401)
76-
with pytest.raises(MindeeHTTPClientException):
76+
with pytest.raises(MindeeHTTPClientError):
7777
raise error_401
7878
assert error_401.status_code == 401
7979
assert error_401.api_code == "Unauthorized"
@@ -85,7 +85,7 @@ def test_http_429_error():
8585
error_ref = open(ERROR_DATA_DIR / "error_429_too_many_requests.json")
8686
error_obj = json.load(error_ref)
8787
error_429 = handle_error("dummy-url", error_obj, 429)
88-
with pytest.raises(MindeeHTTPClientException):
88+
with pytest.raises(MindeeHTTPClientError):
8989
raise error_429
9090
assert error_429.status_code == 429
9191
assert error_429.api_code == "TooManyRequests"
@@ -97,7 +97,7 @@ def test_http_500_error():
9797
error_ref = open(ERROR_DATA_DIR / "error_500_inference_fail.json")
9898
error_obj = json.load(error_ref)
9999
error_500 = handle_error("dummy-url", error_obj, 500)
100-
with pytest.raises(MindeeHTTPServerException):
100+
with pytest.raises(MindeeHTTPServerError):
101101
raise error_500
102102
assert error_500.status_code == 500
103103
assert error_500.api_code == "failure"
@@ -108,7 +108,7 @@ def test_http_500_error():
108108
def test_http_500_html_error():
109109
error_ref_contents = open(ERROR_DATA_DIR / "error_50x.html").read()
110110
error_500 = handle_error("dummy-url", error_ref_contents, 500)
111-
with pytest.raises(MindeeHTTPServerException):
111+
with pytest.raises(MindeeHTTPServerError):
112112
raise error_500
113113
assert error_500.status_code == 500
114114
assert error_500.api_code == "UnknownError"

0 commit comments

Comments
 (0)