Skip to content

Commit e092e38

Browse files
committed
produces more informative errors for unsuccessful requests
1 parent 77df204 commit e092e38

File tree

4 files changed

+84
-2
lines changed

4 files changed

+84
-2
lines changed

tests/test_api_interface.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77
from urllib.parse import unquote
88
from tempfile import gettempdir
99
from os.path import join as path_join
10+
import re
1011

1112
# 3rd party:
1213

1314
# Internal:
1415
from uk_covid19 import Cov19API
16+
from uk_covid19.exceptions import FailedRequestError
1517

1618
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1719

@@ -179,3 +181,26 @@ def test_length_equal(self):
179181

180182
self.assertTrue(csv_len == json_len)
181183
self.assertTrue(csv_len == xml_len)
184+
185+
def test_unsuccessful_request(self):
186+
bad_structure = {
187+
"name": "areaName",
188+
"date": "date",
189+
# Missing the trailing "Date" - making the
190+
# metric name invalid.
191+
"newCases": "newCasesBySpecimen"
192+
}
193+
194+
pattern = re.compile(r"404\s-\sNot Found.*'newCasesBySpecimenDate'", re.S | re.M)
195+
196+
api = Cov19API(filters=test_filters, structure=bad_structure)
197+
198+
with self.assertRaisesRegex(FailedRequestError, pattern):
199+
api.get_json()
200+
201+
with self.assertRaisesRegex(FailedRequestError, pattern):
202+
api.get_xml()
203+
204+
with self.assertRaisesRegex(FailedRequestError, pattern):
205+
api.get_csv()
206+

uk_covid19/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
__copyright__ = "Copyright (c) 2020, Public Health England"
3434
__description__ = "SDK for the COVID-19 API (Coronavirus Dashboard in the UK)"
3535
__license__ = "MIT"
36-
__version__ = "1.1.4"
36+
__version__ = "1.1.5"
3737
__url__ = "https://coronavirus.data.gov.uk/"
3838
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3939

uk_covid19/api_interface.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
# Internal:
1717
from uk_covid19.utils import save_data
18+
from uk_covid19.exceptions import FailedRequestError
1819

1920
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2021

@@ -224,7 +225,8 @@ def _get(self, format_as: str) -> Iterator[Response]:
224225
with request("GET", self.endpoint, params=api_params,
225226
verify=certifi.where()) as response:
226227
if response.status_code >= HTTPStatus.BAD_REQUEST:
227-
raise RuntimeError(f'Request failed: {response.text}')
228+
raise FailedRequestError(response=response, params=api_params)
229+
228230
if response.status_code == HTTPStatus.NO_CONTENT:
229231
self.total_pages = api_params["page"] - 1
230232
break

uk_covid19/exceptions.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/usr/bin python3
2+
3+
# Imports
4+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5+
# Python:
6+
from pprint import pformat
7+
from urllib.parse import unquote
8+
9+
# 3rd party:
10+
from requests import Response
11+
12+
# Internal:
13+
14+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
15+
16+
__all__ = [
17+
'FailedRequestError'
18+
]
19+
20+
21+
class FailedRequestError(RuntimeError):
22+
"""
23+
Exception for failed HTTP request.
24+
"""
25+
26+
message = """
27+
Request failed .... {status_code} - {reason}
28+
Response .......... {response_text}
29+
URL ............... {url}
30+
Decoded URL ........{decoded_url}
31+
Parameters:
32+
{params}
33+
"""
34+
35+
def __init__(self, response: Response, params: dict):
36+
"""
37+
Parameters
38+
----------
39+
response: Response
40+
HTTP request ``Response`` object, as produced by the ``requests``
41+
library.
42+
43+
params: dict
44+
Dictionary of parameters.
45+
"""
46+
message = self.message.format(
47+
status_code=response.status_code,
48+
reason=response.reason,
49+
response_text=response.content.decode() or "No response",
50+
url=response.url,
51+
decoded_url=unquote(response.url),
52+
params=pformat(params, indent=2)
53+
)
54+
55+
super().__init__(message)

0 commit comments

Comments
 (0)