diff --git a/CHANGELOG.md b/CHANGELOG.md index 295aed9..bd49b6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ # Changelog +## v1.6.3 1/27/25 +- Add capability to pull cloudLibrary events by the millisecond + ## v1.6.2 12/2/24 - Add record_num capability to patron_data_helper diff --git a/src/nypl_py_utils/classes/cloudlibrary_client.py b/src/nypl_py_utils/classes/cloudlibrary_client.py index 1c8c191..f871d0e 100644 --- a/src/nypl_py_utils/classes/cloudlibrary_client.py +++ b/src/nypl_py_utils/classes/cloudlibrary_client.py @@ -3,7 +3,7 @@ import hmac import requests -from datetime import datetime, timedelta, timezone +from datetime import datetime, timezone from nypl_py_utils.functions.log_helper import create_log from requests.adapters import HTTPAdapter, Retry @@ -35,28 +35,25 @@ def get_library_events(self, start_date=None, optional timeframe. Pulls past 24 hours of events by default. start_date and end_date are optional parameters, and must be - formatted either YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS + formatted either YYYY-MM-DD, YYYY-MM-DD:SS, or YYYY-MM-DDTHH:MM:SS.fff """ - date_format = "%Y-%m-%dT%H:%M:%S" - today = datetime.now(timezone.utc) - yesterday = today - timedelta(1) - start_date = datetime.strftime( - yesterday, date_format) if start_date is None else start_date - end_date = datetime.strftime( - today, date_format) if end_date is None else end_date - - if (datetime.strptime(start_date, date_format) > - datetime.strptime(end_date, date_format)): - error_message = (f"Start date {start_date} greater than end date " - f"{end_date}, cannot retrieve library events") - self.logger.error(error_message) - raise CloudLibraryClientError(error_message) - - self.logger.info( - (f"Fetching all library events in " - f"time frame {start_date} to {end_date}...")) + path = "data/cloudevents" + if None not in (start_date, end_date): + if (self._parse_event_date(start_date) > + self._parse_event_date(end_date)): + error_message = (f"Start date {start_date} greater than end " + f"date {end_date}, cannot retrieve library " + f"events") + self.logger.error(error_message) + raise CloudLibraryClientError(error_message) + + path += f"?startdate={start_date}&enddate={end_date}" + self.logger.info(f"Fetching all library events in " + f"time frame {start_date} to {end_date}...") + else: + self.logger.info("Fetching all library events " + "from the past day...") - path = f"data/cloudevents?startdate={start_date}&enddate={end_date}" response = self.request(path=path, method_type="GET") return response @@ -66,7 +63,7 @@ def create_request_body(self, request_type, Helper function to generate request body when performing item and/or patron-specific functions (ex. checking out a title). """ - request_template = "<%(request_type)s>%(item_id)s%(patron_id)s" # noqa + request_template = "<%(request_type)s>%(item_id)s%(patron_id)s" # noqa return request_template % { "request_type": request_type, "item_id": item_id, @@ -113,6 +110,16 @@ def request(self, path, method_type="GET", return response + def _parse_event_date(self, event_date) -> datetime: + for fmt in ("%Y-%m-%d", "%Y-%m-%dT%H:%M:%S", "%Y-%m-%dT%H:%M:%S.%f"): + try: + return datetime.strptime(event_date, fmt) + except ValueError: + pass + error_message = (f"Invalid date format found: {event_date}") + self.logger.error(error_message) + raise CloudLibraryClientError(error_message) + def _build_headers(self, method_type, path) -> dict: time, authorization = self._build_authorization( method_type, path) diff --git a/tests/test_cloudlibrary_client.py b/tests/test_cloudlibrary_client.py index 84866f9..188c6ef 100644 --- a/tests/test_cloudlibrary_client.py +++ b/tests/test_cloudlibrary_client.py @@ -41,17 +41,13 @@ def test_instance(self): def test_get_library_events_success_no_args( self, test_instance, mocker): - start = "2024-11-10T10:00:00" - end = "2024-11-11T10:00:00" mock_request = mocker.patch( - "nypl_py_utils.classes.cloudlibrary_client.CloudLibraryClient.request", # noqa - return_value=_TEST_LIBRARY_EVENTS_RESPONSE) - response = test_instance.get_library_events() + "nypl_py_utils.classes.cloudlibrary_client.CloudLibraryClient.request") # noqa + test_instance.get_library_events() mock_request.assert_called_once_with( - path=f"data/cloudevents?startdate={start}&enddate={end}", + path="data/cloudevents", method_type="GET") - assert response == _TEST_LIBRARY_EVENTS_RESPONSE def test_get_library_events_success_with_start_and_end_date( self, test_instance, mocker): @@ -67,20 +63,6 @@ def test_get_library_events_success_with_start_and_end_date( method_type="GET") assert response == _TEST_LIBRARY_EVENTS_RESPONSE - def test_get_library_events_success_with_no_end_date( - self, test_instance, mocker): - start = "2024-11-01T09:00:00" - end = "2024-11-11T10:00:00" - mock_request = mocker.patch( - "nypl_py_utils.classes.cloudlibrary_client.CloudLibraryClient.request", # noqa - return_value=_TEST_LIBRARY_EVENTS_RESPONSE) - response = test_instance.get_library_events(start) - - mock_request.assert_called_once_with( - path=f"data/cloudevents?startdate={start}&enddate={end}", - method_type="GET") - assert response == _TEST_LIBRARY_EVENTS_RESPONSE - def test_get_library_events_exception_when_start_date_greater_than_end( self, test_instance, caplog): start = "2024-11-11T09:00:00" @@ -103,7 +85,7 @@ def test_get_library_events_exception_when_connection_timeout( url, exc=ConnectTimeout) with pytest.raises(CloudLibraryClientError): - test_instance.get_library_events() + test_instance.get_library_events(start, end) assert (f"Failed to retrieve response from {url}") in caplog.text def test_get_request_success(self, test_instance, requests_mock):