From 59c340f4411c704d7c86debeacc6ddde43e02f9d Mon Sep 17 00:00:00 2001 From: giacomounivr Date: Wed, 18 Dec 2024 12:31:28 +0100 Subject: [PATCH] add response URL caching and tests --- iiif_prezi3/helpers/set_hwd_from_iiif.py | 40 +++++++++++++++++------- tests/test_set_hwd_from_iiif.py | 18 +++++++---- 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/iiif_prezi3/helpers/set_hwd_from_iiif.py b/iiif_prezi3/helpers/set_hwd_from_iiif.py index b1ab792..0ebabb5 100644 --- a/iiif_prezi3/helpers/set_hwd_from_iiif.py +++ b/iiif_prezi3/helpers/set_hwd_from_iiif.py @@ -1,13 +1,33 @@ +from functools import lru_cache import requests from ..loader import monkeypatch_schema from ..skeleton import Canvas, Resource, ResourceItem +@lru_cache(maxsize=3) +def get_info_json(url): + """Cache the info.json response of the URL request. + + Args: + url (str): An HTTP URL for the IIIF image endpoint. + + Returns: + dict: The info.json as a dictionary. + """ + response = requests.get(url) + # if response is not 200, raise exception + if response.status_code != requests.codes.ok: + response.raise_for_status() + # if response is not valid json, request will raise + # requests.exceptions.JSONDecodeError + # — handle or document and let calling code handle? + return response.json() + + class SetHwdFromIIIF: # should probably be added to canvas helpers - - def set_hwd_from_iiif(self, url): + def set_hwd_from_iiif(self, url, use_cache=True): """Set height and width on a Canvas object. Requests IIIF Image information remotely for an @@ -16,22 +36,18 @@ def set_hwd_from_iiif(self, url): Args: url (str): An HTTP URL for the IIIF image endpoint. + use_cache (bool): If True multiple requests to the same URL will + use the cached response without making new requests to the server + (default True). """ # resource url may or may not end with info.json; # add if not present if not url.endswith("info.json"): url = f"{ url.rstrip('/') }/info.json" - - response = requests.get(url) - # if response is not 200, raise exception - if response.status_code != requests.codes.ok: - response.raise_for_status() - # if response is not valid json, request will raise - # requests.exceptions.JSONDecodeError - # — handle or document and let calling code handle? - resource_info = response.json() + resource_info = ( + get_info_json(url) if use_cache else get_info_json.__wrapped__(url) + ) self.set_hwd(resource_info.get("height"), resource_info.get("width")) - return resource_info diff --git a/tests/test_set_hwd_from_iiif.py b/tests/test_set_hwd_from_iiif.py index 5d91a19..da628ce 100644 --- a/tests/test_set_hwd_from_iiif.py +++ b/tests/test_set_hwd_from_iiif.py @@ -16,17 +16,17 @@ def test_set_hwd_from_iiif(self, mockrequest_get): image_id = 'http://iiif.example.org/images/1234abcd' image_info_url = f'{image_id}/info.json' # image api url without info.json - self.canvas.set_hwd_from_iiif(image_id) + self.canvas.set_hwd_from_iiif(image_id, use_cache=False) mockrequest_get.assert_called_with(image_info_url) # image api url with info.json mockrequest_get.reset_mock() - self.canvas.set_hwd_from_iiif(image_id) + self.canvas.set_hwd_from_iiif(image_id, use_cache=False) mockrequest_get.assert_called_with(image_info_url) # image url with trailing slash mockrequest_get.reset_mock() - self.canvas.set_hwd_from_iiif(image_id + "/") + self.canvas.set_hwd_from_iiif(image_id + "/", use_cache=False) mockrequest_get.assert_called_with(image_info_url) # non-200 response @@ -37,7 +37,7 @@ def test_set_hwd_from_iiif(self, mockrequest_get): mockresponse.raise_for_status.side_effect = requests.exceptions.HTTPError mockrequest_get.return_value = mockresponse with self.assertRaises(requests.exceptions.HTTPError): - self.canvas.set_hwd_from_iiif(image_id) + self.canvas.set_hwd_from_iiif(image_id, use_cache=False) # non-200 should raise exception for status mockresponse.raise_for_status.assert_called_once() @@ -45,7 +45,7 @@ def test_set_hwd_from_iiif(self, mockrequest_get): mockresponse.status_code = 200 mockresponse.json.side_effect = requests.exceptions.JSONDecodeError("", "", 0) # JSONDecodeError needs arguments with self.assertRaises(requests.exceptions.JSONDecodeError): - self.canvas.set_hwd_from_iiif(image_id) + self.canvas.set_hwd_from_iiif(image_id, use_cache=False) # successful response with dimensions mockresponse.json.side_effect = None @@ -59,5 +59,11 @@ def test_set_hwd_from_iiif(self, mockrequest_get): } # patch the method this helper calls so we can inspect with patch.object(Canvas, 'set_hwd') as mock_set_hwd: - self.canvas.set_hwd_from_iiif(image_id) + self.canvas.set_hwd_from_iiif(image_id, use_cache=False) mock_set_hwd.assert_called_with(6608, 4821) + + # we test the caching mechanism + self.canvas.set_hwd_from_iiif(image_id, use_cache=True) # will call get + mockrequest_get.reset_mock() + self.canvas.set_hwd_from_iiif(image_id, use_cache=True) # should not + mockrequest_get.assert_not_called()