Skip to content

Commit

Permalink
fix: timestamp parsing (#156)
Browse files Browse the repository at this point in the history
* fix: timestamp parsing

* tests: fix CI

* style: fix docstring
  • Loading branch information
wochinge authored Feb 2, 2024
1 parent b16ed03 commit 7ced654
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 5 deletions.
3 changes: 2 additions & 1 deletion deepset_cloud_sdk/_api/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

from deepset_cloud_sdk._api.deepset_cloud_api import DeepsetCloudAPI
from deepset_cloud_sdk._api.upload_sessions import WriteMode
from deepset_cloud_sdk._utils.datetime import from_isoformat

logger = structlog.get_logger(__name__)

Expand Down Expand Up @@ -54,7 +55,7 @@ def from_dict(cls, env: Dict[str, Any]) -> Any:
:param env: Dictionary to parse.
"""
to_parse = {k: v for k, v in env.items() if k in inspect.signature(cls).parameters}
to_parse["created_at"] = datetime.datetime.fromisoformat(to_parse["created_at"])
to_parse["created_at"] = from_isoformat(to_parse["created_at"])
to_parse["file_id"] = UUID(to_parse["file_id"])
return cls(**to_parse)

Expand Down
9 changes: 5 additions & 4 deletions deepset_cloud_sdk/_api/upload_sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from tenacity import retry, retry_if_exception_type, stop_after_attempt, wait_fixed

from deepset_cloud_sdk._api.deepset_cloud_api import DeepsetCloudAPI
from deepset_cloud_sdk._utils.datetime import from_isoformat
from deepset_cloud_sdk.models import UserInfo

logger = structlog.get_logger(__name__)
Expand Down Expand Up @@ -146,7 +147,7 @@ async def create(self, workspace_name: str, write_mode: WriteMode = WriteMode.KE
return UploadSession(
session_id=UUID(response_body["session_id"]),
documentation_url=response_body["documentation_url"],
expires_at=datetime.datetime.fromisoformat(response_body["expires_at"]),
expires_at=from_isoformat(response_body["expires_at"]),
aws_prefixed_request_config=AWSPrefixedRequestConfig(
fields=response_body["aws_prefixed_request_config"]["fields"],
url=response_body["aws_prefixed_request_config"]["url"],
Expand Down Expand Up @@ -211,7 +212,7 @@ async def status(self, workspace_name: str, session_id: UUID) -> UploadSessionSt
return UploadSessionStatus(
session_id=UUID(response_body["session_id"]),
documentation_url=response_body["documentation_url"],
expires_at=datetime.datetime.fromisoformat(response_body["expires_at"]),
expires_at=from_isoformat(response_body["expires_at"]),
ingestion_status=UploadSessionIngestionStatus(
failed_files=response_body["ingestion_status"]["failed_files"],
finished_files=response_body["ingestion_status"]["finished_files"],
Expand Down Expand Up @@ -267,8 +268,8 @@ async def list(
given_name=upload_session["created_by"]["given_name"],
family_name=upload_session["created_by"]["family_name"],
),
expires_at=datetime.datetime.fromisoformat(upload_session["expires_at"]),
created_at=datetime.datetime.fromisoformat(upload_session["created_at"]),
expires_at=from_isoformat(upload_session["expires_at"]),
created_at=from_isoformat(upload_session["created_at"]),
write_mode=UploadSessionWriteModeEnum(upload_session["write_mode"]),
status=UploadSessionStatusEnum(upload_session["status"]),
)
Expand Down
12 changes: 12 additions & 0 deletions deepset_cloud_sdk/_utils/datetime.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"""Utility functions for working with datetime objects."""
from datetime import datetime


def from_isoformat(date_str: str) -> datetime:
"""Parse a date string in ISO 8601 format and returns a datetime object.
Our new Pydantic 2.0 API returns with the `Z` suffix, but the old one returns with `+00:00`
Python versions < 3.12 don't support the `Z` suffix, so we need to replace it with `+00:00`
"""
date_str = date_str.replace("Z", "+00:00")
return datetime.fromisoformat(date_str)
43 changes: 43 additions & 0 deletions tests/unit/api/test_upload_sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,49 @@ async def test_list_sessions(
assert result.data[0].write_mode == UploadSessionWriteModeEnum.KEEP
assert result.data[0].status == UploadSessionStatusEnum.OPEN

async def test_list_sessions_with_z_timestamp(
self, upload_session_client: UploadSessionsAPI, mocked_deepset_cloud_api: Mock
) -> None:
session_id = uuid4()
timestamp = datetime.datetime.now()
user_id = uuid4()

mocked_deepset_cloud_api.get.return_value = Response(
status_code=codes.OK,
json={
"data": [
{
"session_id": str(session_id),
"created_by": {
"given_name": "Kristof",
"family_name": "Test",
"user_id": str(user_id),
},
"created_at": timestamp.isoformat().replace("+00:00", "Z"),
"expires_at": timestamp.isoformat().replace("+00:00", "Z"),
"write_mode": "KEEP",
"status": "OPEN",
},
],
"has_more": True,
"total": 23,
},
)
result: UploadSessionDetailList = await upload_session_client.list(
workspace_name="sdk_read", is_expired=True, limit=1, page_number=10
)
assert result.has_more is True
assert result.total == 23
assert len(result.data) == 1
assert result.data[0].session_id == session_id
assert result.data[0].created_by.given_name == "Kristof"
assert result.data[0].created_by.family_name == "Test"
assert result.data[0].created_by.user_id == user_id
assert result.data[0].created_at == timestamp
assert result.data[0].expires_at == timestamp
assert result.data[0].write_mode == UploadSessionWriteModeEnum.KEEP
assert result.data[0].status == UploadSessionStatusEnum.OPEN

@pytest.mark.parametrize("first_status_code", [codes.BAD_GATEWAY, codes.INTERNAL_SERVER_ERROR])
async def test_list_sessions_with_retry(
self, upload_session_client: UploadSessionsAPI, mocked_deepset_cloud_api: Mock, first_status_code: int
Expand Down
17 changes: 17 additions & 0 deletions tests/unit/utils/test_datetime_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from datetime import datetime, timezone

import pytest

from deepset_cloud_sdk._utils.datetime import from_isoformat


class TestFromIsoformat:
@pytest.mark.parametrize(
"input",
[
"2024-02-03T08:10:10.335884Z",
"2024-02-03T08:10:10.335884+00:00",
],
)
def test_fromisoformat(self, input: str) -> None:
assert from_isoformat(input) == datetime(2024, 2, 3, 8, 10, 10, 335884).replace(tzinfo=timezone.utc)

0 comments on commit 7ced654

Please sign in to comment.