Skip to content

Commit 675e07c

Browse files
xalelaxheitorPB
andauthored
feat: Raise proper error (ValidationError) for invalid inputs (#67)
#### Relevant issue or PR Close #19 #### Description of changes If HTTPClient gets a 422 response (validation error), its context is parsed and reraised as a pydantic ValidationError #### Testing done Added a unit test + tested locally on vectoradd with ```python from tesseract_core import Tesseract import numpy as np a = np.array([1.0, 2.0, 3.0]) b = np.array([1.0, 2.0, 3.0]) with Tesseract.from_image("vectoradd") as t: t.apply({"whoops": "whatever"}) ``` #### License - [ x] By submitting this pull request, I confirm that my contribution is made under the terms of the [Apache 2.0 license](https://pasteurlabs.github.io/tesseract/LICENSE). - [ x] I sign the Developer Certificate of Origin below by adding my name and email address to the `Signed-off-by` line. <details> <summary><b>Developer Certificate of Origin</b></summary> ```text Developer Certificate of Origin Version 1.1 Copyright (C) 2004, 2006 The Linux Foundation and its contributors. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. ``` </details> Signed-off-by: Alessandro Angioi <alessandro.angioi@simulation.science> --------- Co-authored-by: Heitor de Bittencourt <heitorpbittencourt@gmail.com>
1 parent d18ee0c commit 675e07c

File tree

2 files changed

+56
-2
lines changed

2 files changed

+56
-2
lines changed

tesseract_core/sdk/tesseract.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
import numpy as np
1313
import requests
14+
from pydantic import ValidationError
15+
from pydantic_core import InitErrorDetails
1416

1517
from . import engine
1618

@@ -313,10 +315,24 @@ def _request(
313315
encoded_payload = None
314316

315317
response = requests.request(method=method, url=url, json=encoded_payload)
316-
response.raise_for_status()
317-
318318
data = response.json()
319319

320+
if (
321+
response.status_code == requests.codes.unprocessable_entity
322+
and "detail" in data
323+
):
324+
errors = [
325+
InitErrorDetails(
326+
type=e["type"],
327+
loc=tuple(e["loc"]),
328+
input=e.get("input"),
329+
)
330+
for e in data["detail"]
331+
]
332+
raise ValidationError.from_exception_data(f"endpoint {endpoint}", errors)
333+
else:
334+
response.raise_for_status()
335+
320336
if endpoint in [
321337
"apply",
322338
"jacobian",

tests/sdk_tests/test_tesseract.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import numpy as np
22
import pytest
3+
from pydantic import ValidationError
34

45
from tesseract_core import Tesseract
56
from tesseract_core.sdk.tesseract import (
@@ -108,6 +109,43 @@ def test_HTTPClient_run_tesseract(mocker):
108109
)
109110

110111

112+
def test_HTTPClient__run_tesseract_raises_validation_error(mocker):
113+
mock_response = mocker.Mock()
114+
mock_response.json.return_value = {
115+
"detail": [
116+
{
117+
"type": "missing",
118+
"loc": ["body", "inputs", "a"],
119+
"msg": "Field required",
120+
"input": {"whoops": "whatever"},
121+
},
122+
{
123+
"type": "missing",
124+
"loc": ["body", "inputs", "b"],
125+
"msg": "Field required",
126+
"input": {"whoops": "whatever"},
127+
},
128+
{
129+
"type": "extra_forbidden",
130+
"loc": ["body", "inputs", "whoops"],
131+
"msg": "Extra inputs are not permitted",
132+
"input": "whatever",
133+
},
134+
]
135+
}
136+
mock_response.status_code = 422
137+
138+
mocker.patch(
139+
"requests.request",
140+
return_value=mock_response,
141+
)
142+
143+
client = HTTPClient("somehost")
144+
145+
with pytest.raises(ValidationError):
146+
client._run_tesseract("apply", {"inputs": {"whoops": "whatever"}})
147+
148+
111149
@pytest.mark.parametrize(
112150
"b64, expected_data",
113151
[

0 commit comments

Comments
 (0)