Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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

Expand Down
51 changes: 29 additions & 22 deletions src/nypl_py_utils/classes/cloudlibrary_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand All @@ -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><ItemId>%(item_id)s</ItemId><PatronId>%(patron_id)s</PatronId></%(request_type)s>" # noqa
request_template = "<%(request_type)s><ItemId>%(item_id)s</ItemId><PatronId>%(patron_id)s</PatronId></%(request_type)s>" # noqa
return request_template % {
"request_type": request_type,
"item_id": item_id,
Expand Down Expand Up @@ -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)
Expand Down
26 changes: 4 additions & 22 deletions tests/test_cloudlibrary_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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"
Expand All @@ -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):
Expand Down