Skip to content

Commit 5809d01

Browse files
committed
return none if last used at is returned with GO's zero date
1 parent df418d0 commit 5809d01

2 files changed

Lines changed: 31 additions & 12 deletions

File tree

mock_tests/test_users.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,3 +202,21 @@ def handler(request: Request) -> Response:
202202
assert user is not None
203203
assert user.last_used_time == EXPECTED_LAST_USED_AT
204204
assert captured["params"].get("includeLastUsedTime") in ("False", "false")
205+
206+
207+
def test_get_user_go_zero_time_treated_as_none(
208+
weaviate_no_auth_mock: HTTPServer, start_grpc_server: grpc.Server
209+
) -> None:
210+
"""Go's zero time (0001-01-01T00:00:00Z) returned by the server should map to None."""
211+
data = {**USER_DATA, "lastUsedAt": "0001-01-01T00:00:00Z"}
212+
weaviate_no_auth_mock.expect_request("/v1/users/db/test-user").respond_with_response(
213+
Response(json.dumps(data), content_type="application/json", status=200)
214+
)
215+
216+
with weaviate.connect_to_local(
217+
host=MOCK_IP, port=MOCK_PORT, grpc_port=MOCK_PORT_GRPC
218+
) as client:
219+
user = client.users.db.get(user_id="test-user")
220+
221+
assert user is not None
222+
assert user.last_used_time is None

weaviate/users/base.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from datetime import datetime
1+
from datetime import datetime, timezone
22
from typing import Any, Dict, Generic, List, Literal, Optional, Union, cast, overload
33

44
from httpx import Response
@@ -21,6 +21,16 @@
2121
)
2222
from weaviate.util import _decode_json_response_dict, escape_string
2323

24+
# Go's zero time value, returned by the server when a timestamp is not set
25+
_GO_ZERO_TIME = datetime(1, 1, 1, 0, 0, tzinfo=timezone.utc)
26+
27+
28+
def _parse_last_used_at(value: Optional[str]) -> Optional[datetime]:
29+
if value is None:
30+
return None
31+
dt = datetime.fromisoformat(value.replace("Z", "+00:00"))
32+
return None if dt == _GO_ZERO_TIME else dt
33+
2434

2535
class _BaseExecutor(Generic[ConnectionType]):
2636
def __init__(self, connection: ConnectionType):
@@ -468,7 +478,6 @@ def resp(res: Response) -> Optional[UserDB]:
468478
parsed = _decode_json_response_dict(res, "Get user")
469479
assert parsed is not None
470480
created_at = parsed.get("createdAt")
471-
last_used_at = parsed.get("lastUsedAt")
472481
return UserDB(
473482
user_id=parsed["userId"],
474483
role_names=parsed["roles"],
@@ -479,11 +488,7 @@ def resp(res: Response) -> Optional[UserDB]:
479488
if created_at is not None
480489
else None
481490
),
482-
last_used_time=(
483-
datetime.fromisoformat(last_used_at.replace("Z", "+00:00"))
484-
if last_used_at is not None
485-
else None
486-
),
491+
last_used_time=_parse_last_used_at(parsed.get("lastUsedAt")),
487492
api_key_first_letters=parsed.get("apiKeyFirstLetters"),
488493
)
489494

@@ -517,11 +522,7 @@ def resp(res: Response) -> List[UserDB]:
517522
if (ca := user.get("createdAt")) is not None
518523
else None
519524
),
520-
last_used_time=(
521-
datetime.fromisoformat(lua.replace("Z", "+00:00"))
522-
if (lua := user.get("lastUsedAt")) is not None
523-
else None
524-
),
525+
last_used_time=_parse_last_used_at(user.get("lastUsedAt")),
525526
api_key_first_letters=user.get("apiKeyFirstLetters"),
526527
)
527528
for user in cast(List[WeaviateDBUserRoleNames], parsed)

0 commit comments

Comments
 (0)