Skip to content

Commit c6810a6

Browse files
authored
Merge pull request #1337 from OCR-D/improve-network-client-errors
Improve ocrd-network-client error handling
2 parents fd91159 + ccbb5e7 commit c6810a6

File tree

2 files changed

+96
-25
lines changed

2 files changed

+96
-25
lines changed

src/ocrd_network/cli/client.py

Lines changed: 71 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import sys
12
import click
23
from json import dumps
34
from typing import List, Optional, Tuple
@@ -10,11 +11,13 @@
1011
from ocrd_utils.introspect import set_json_key_value_overrides
1112
from ocrd_utils.str import parse_json_string_or_file
1213
from ..client import Client
14+
from requests import RequestException
1315

1416

1517
ADDRESS_HELP = 'The URL of the Processing Server. If not provided, ' + \
1618
'the "OCRD_NETWORK_SERVER_ADDR_PROCESSING" environment variable is used by default'
1719

20+
1821
class URLType(click.types.StringParamType):
1922
name = "url"
2023
def convert(self, value, param, ctx):
@@ -53,7 +56,14 @@ def check_deployed_processors(address: Optional[str]):
5356
Each processor is shown only once regardless of the amount of deployed instances.
5457
"""
5558
client = Client(server_addr_processing=address)
56-
processors_list = client.check_deployed_processors()
59+
try:
60+
processors_list = client.check_deployed_processors()
61+
except RequestException as e:
62+
print(
63+
getattr(e, 'detail_message', str(e)),
64+
f"Requested URL: {getattr(getattr(e, 'response', ''), 'url', '')}"
65+
)
66+
sys.exit(1)
5767
print(dumps(processors_list, indent=4))
5868

5969

@@ -65,7 +75,14 @@ def check_processor_ocrd_tool(address: Optional[str], processor_name: str):
6575
Get the json tool of a deployed processor specified with `processor_name`
6676
"""
6777
client = Client(server_addr_processing=address)
68-
ocrd_tool = client.check_deployed_processor_ocrd_tool(processor_name=processor_name)
78+
try:
79+
ocrd_tool = client.check_deployed_processor_ocrd_tool(processor_name=processor_name)
80+
except RequestException as e:
81+
print(
82+
getattr(e, 'detail_message', str(e)),
83+
f"Requested URL: {getattr(getattr(e, 'response', ''), 'url', '')}"
84+
)
85+
sys.exit(1)
6986
print(dumps(ocrd_tool, indent=4))
7087

7188

@@ -85,7 +102,14 @@ def check_processing_job_log(address: Optional[str], processing_job_id: str):
85102
Check the log of a previously submitted processing job.
86103
"""
87104
client = Client(server_addr_processing=address)
88-
response = client.check_job_log(job_id=processing_job_id)
105+
try:
106+
response = client.check_job_log(job_id=processing_job_id)
107+
except RequestException as e:
108+
print(
109+
getattr(e, 'detail_message', str(e)),
110+
f"Requested URL: {getattr(getattr(e, 'response', ''), 'url', '')}"
111+
)
112+
sys.exit(1)
89113
print(response._content.decode(encoding='utf-8'))
90114

91115

@@ -97,8 +121,14 @@ def check_processing_job_status(address: Optional[str], processing_job_id: str):
97121
Check the status of a previously submitted processing job.
98122
"""
99123
client = Client(server_addr_processing=address)
100-
job_status = client.check_job_status(processing_job_id)
101-
assert job_status
124+
try:
125+
job_status = client.check_job_status(processing_job_id)
126+
except RequestException as e:
127+
print(
128+
getattr(e, 'detail_message', str(e)),
129+
f"Requested URL: {getattr(getattr(e, 'response', ''), 'url', '')}"
130+
)
131+
sys.exit(1)
102132
print(f"Processing job status: {job_status}")
103133

104134

@@ -154,12 +184,26 @@ def send_processing_job_request(
154184
if callback_url:
155185
req_params["callback_url"] = callback_url
156186
client = Client(server_addr_processing=address)
157-
processing_job_id = client.send_processing_job_request(
158-
processor_name=processor_name, req_params=req_params)
159-
assert processing_job_id
187+
try:
188+
processing_job_id = client.send_processing_job_request(
189+
processor_name=processor_name, req_params=req_params)
190+
except RequestException as e:
191+
print(
192+
getattr(e, 'detail_message', str(e)),
193+
f"Requested URL: {getattr(getattr(e, 'response', ''), 'url', '')}"
194+
)
195+
sys.exit(1)
160196
print(f"Processing job id: {processing_job_id}")
197+
161198
if block:
162-
client.poll_job_status(job_id=processing_job_id, print_state=print_state)
199+
try:
200+
client.poll_job_status(job_id=processing_job_id, print_state=print_state)
201+
except RequestException as e:
202+
print(
203+
getattr(e, 'detail_message', str(e)),
204+
f"Requested URL: {getattr(getattr(e, 'response', ''), 'url', '')}"
205+
)
206+
sys.exit(1)
163207

164208

165209
@client_cli.group('workflow')
@@ -178,8 +222,14 @@ def check_workflow_job_status(address: Optional[str], workflow_job_id: str):
178222
Check the status of a previously submitted workflow job.
179223
"""
180224
client = Client(server_addr_processing=address)
181-
job_status = client.check_workflow_status(workflow_job_id)
182-
assert job_status
225+
try:
226+
job_status = client.check_workflow_status(workflow_job_id)
227+
except RequestException as e:
228+
print(
229+
getattr(e, 'detail_message', str(e)),
230+
f"Requested URL: {getattr(getattr(e, 'response', ''), 'url', '')}"
231+
)
232+
sys.exit(1)
183233
print(f"Workflow job status: {job_status}")
184234

185235

@@ -209,7 +259,8 @@ def send_workflow_job_request(
209259
as in ``ocrd process`` tasks arguments), or via `-w` file path
210260
(same syntax, but newline separated).
211261
"""
212-
assert bool(path_to_workflow) != bool(len(tasks)), "requires either --path-to-workflow or task arguments"
262+
if (path_to_workflow) != bool(len(tasks)):
263+
raise ValueError("either -w/path-to-workflow or task argument(s) is required")
213264

214265
client = Client(server_addr_processing=address)
215266
with NamedTemporaryFile() as workflow_file:
@@ -221,11 +272,17 @@ def send_workflow_job_request(
221272
path_to_mets=path_to_mets,
222273
page_wise=page_wise,
223274
)
224-
assert workflow_job_id
225275
print(f"Workflow job id: {workflow_job_id}")
226276
if block:
227277
print(f"Polling state of workflow job {workflow_job_id}")
228-
state = client.poll_workflow_status(job_id=workflow_job_id, print_state=print_state)
278+
try:
279+
state = client.poll_workflow_status(job_id=workflow_job_id, print_state=print_state)
280+
except RequestException as e:
281+
print(
282+
getattr(e, 'detail_message', str(e)),
283+
f"Requested URL: {getattr(getattr(e, 'response', ''), 'url', '')}"
284+
)
285+
sys.exit(1)
229286
if state != JobState.success:
230287
print(f"Workflow failed with {state}")
231288
exit(1)

src/ocrd_network/client_utils.py

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import json
22
import os
3-
from requests import get as request_get, post as request_post
3+
from requests import get as request_get, post as request_post, RequestException, Response
4+
from requests.exceptions import JSONDecodeError
45
from time import sleep
56
from .constants import JobState, NETWORK_PROTOCOLS
67

@@ -24,6 +25,19 @@ def _poll_endpoint_status(ps_server_host: str, job_id: str, job_type: str, tries
2425
return job_state
2526

2627

28+
def _raise_if_error(response: Response) -> None:
29+
"""Check the requests-response and raise an exception if its status code indicates an error"""
30+
try:
31+
response.raise_for_status()
32+
except RequestException as e:
33+
try:
34+
message = response.json()["detail"]
35+
except JSONDecodeError:
36+
message = response.text
37+
e.detail_message = message
38+
raise e
39+
40+
2741
def poll_job_status_till_timeout_fail_or_success(
2842
ps_server_host: str, job_id: str, tries: int, wait: int, print_state: bool = False) -> JobState:
2943
return _poll_endpoint_status(ps_server_host, job_id, "processor", tries, wait, print_state)
@@ -37,14 +51,14 @@ def poll_wf_status_till_timeout_fail_or_success(
3751
def get_ps_deployed_processors(ps_server_host: str):
3852
request_url = f"{ps_server_host}/processor"
3953
response = request_get(url=request_url, headers={"accept": "application/json; charset=utf-8"})
40-
assert response.status_code == 200, f"Processing server: {request_url}, {response.status_code}"
54+
_raise_if_error(response)
4155
return response.json()
4256

4357

4458
def get_ps_deployed_processor_ocrd_tool(ps_server_host: str, processor_name: str):
4559
request_url = f"{ps_server_host}/processor/info/{processor_name}"
4660
response = request_get(url=request_url, headers={"accept": "application/json; charset=utf-8"})
47-
assert response.status_code == 200, f"Processing server: {request_url}, {response.status_code}"
61+
_raise_if_error(response)
4862
return response.json()
4963

5064

@@ -57,18 +71,18 @@ def get_ps_processing_job_log(ps_server_host: str, processing_job_id: str):
5771
def get_ps_processing_job_status(ps_server_host: str, processing_job_id: str) -> JobState:
5872
request_url = f"{ps_server_host}/processor/job/{processing_job_id}"
5973
response = request_get(url=request_url, headers={"accept": "application/json; charset=utf-8"})
60-
assert response.status_code == 200, f"Processing server: {request_url}, {response.status_code}"
74+
_raise_if_error(response)
6175
job_state = response.json()["state"]
62-
assert job_state
76+
assert job_state, "Propery 'state' is expected to always have a value"
6377
return getattr(JobState, job_state.lower())
6478

6579

6680
def get_ps_workflow_job_status(ps_server_host: str, workflow_job_id: str) -> JobState:
6781
request_url = f"{ps_server_host}/workflow/job-simple/{workflow_job_id}"
6882
response = request_get(url=request_url, headers={"accept": "application/json; charset=utf-8"})
69-
assert response.status_code == 200, f"Processing server: {request_url}, {response.status_code}"
83+
_raise_if_error(response)
7084
job_state = response.json()["state"]
71-
assert job_state
85+
assert job_state, "Property 'state' is expected to always have a value"
7286
return getattr(JobState, job_state.lower())
7387

7488

@@ -79,9 +93,9 @@ def post_ps_processing_request(ps_server_host: str, processor: str, job_input: d
7993
headers={"accept": "application/json; charset=utf-8"},
8094
json=job_input
8195
)
82-
assert response.status_code == 200, f"Processing server: {request_url}, {response.status_code}"
96+
_raise_if_error(response)
8397
processing_job_id = response.json()["job_id"]
84-
assert processing_job_id
98+
assert processing_job_id, "Property 'job_id' is expected to always have a value"
8599
return processing_job_id
86100

87101

@@ -102,9 +116,9 @@ def post_ps_workflow_request(
102116
json_resp_raw = response.text
103117
# print(f'post_ps_workflow_request >> {response.status_code}')
104118
# print(f'post_ps_workflow_request >> {json_resp_raw}')
105-
assert response.status_code == 200, f"Processing server: {request_url}, {response.status_code}"
119+
_raise_if_error(response)
106120
wf_job_id = json.loads(json_resp_raw)["job_id"]
107-
assert wf_job_id
121+
assert wf_job_id, "Property 'job_id' is expected to always have a value"
108122
return wf_job_id
109123

110124

0 commit comments

Comments
 (0)