diracx-db 0.0.1a49__tar.gz → 0.0.1a50__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/PKG-INFO +1 -1
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/auth/schema.py +6 -2
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/utils/__init__.py +15 -11
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/utils/base.py +33 -1
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/tests/auth/test_refresh_token.py +0 -2
- diracx_db-0.0.1a50/tests/utils/test_uuid.py +221 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/.gitignore +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/README.md +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/pyproject.toml +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/__init__.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/__main__.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/exceptions.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/os/__init__.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/os/job_parameters.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/os/utils.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/py.typed +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/__init__.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/auth/__init__.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/auth/db.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/dummy/__init__.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/dummy/db.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/dummy/schema.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/job/__init__.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/job/db.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/job/schema.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/job_logging/__init__.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/job_logging/db.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/job_logging/schema.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/pilot_agents/__init__.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/pilot_agents/db.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/pilot_agents/schema.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/sandbox_metadata/__init__.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/sandbox_metadata/db.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/sandbox_metadata/schema.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/task_queue/__init__.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/task_queue/db.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/task_queue/schema.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/utils/functions.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/src/diracx/db/sql/utils/types.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/tests/auth/test_authorization_flow.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/tests/auth/test_device_flow.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/tests/jobs/test_job_db.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/tests/jobs/test_job_logging_db.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/tests/jobs/test_sandbox_metadata.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/tests/opensearch/test_connection.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/tests/opensearch/test_index_template.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/tests/opensearch/test_search.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/tests/pilot_agents/__init__.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/tests/pilot_agents/test_pilot_agents_db.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/tests/test_dummy_db.py +0 -0
- {diracx_db-0.0.1a49 → diracx_db-0.0.1a50}/tests/test_freeze_time.py +0 -0
@@ -10,7 +10,12 @@ from sqlalchemy import (
|
|
10
10
|
)
|
11
11
|
from sqlalchemy.orm import declarative_base
|
12
12
|
|
13
|
-
from diracx.db.sql.utils import
|
13
|
+
from diracx.db.sql.utils import (
|
14
|
+
Column,
|
15
|
+
DateNowColumn,
|
16
|
+
EnumColumn,
|
17
|
+
NullColumn,
|
18
|
+
)
|
14
19
|
|
15
20
|
USER_CODE_LENGTH = 8
|
16
21
|
|
@@ -92,7 +97,6 @@ class RefreshTokens(Base):
|
|
92
97
|
status = EnumColumn(
|
93
98
|
"Status", RefreshTokenStatus, server_default=RefreshTokenStatus.CREATED.name
|
94
99
|
)
|
95
|
-
creation_time = DateNowColumn("CreationTime", index=True)
|
96
100
|
scope = Column("Scope", String(1024))
|
97
101
|
|
98
102
|
# User attributes bound to the refresh token
|
@@ -1,16 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
|
4
|
-
BaseSQLDB,
|
5
|
-
SQLDBUnavailableError,
|
6
|
-
_get_columns,
|
7
|
-
apply_search_filters,
|
8
|
-
apply_sort_constraints,
|
9
|
-
)
|
10
|
-
from .functions import hash, substract_date, utcnow
|
11
|
-
from .types import Column, DateNowColumn, EnumBackedBool, EnumColumn, NullColumn
|
12
|
-
|
13
|
-
__all__ = (
|
3
|
+
__all__ = [
|
14
4
|
"_get_columns",
|
15
5
|
"utcnow",
|
16
6
|
"Column",
|
@@ -24,4 +14,18 @@ __all__ = (
|
|
24
14
|
"substract_date",
|
25
15
|
"hash",
|
26
16
|
"SQLDBUnavailableError",
|
17
|
+
"uuid7_from_datetime",
|
18
|
+
"uuid7_to_datetime",
|
19
|
+
]
|
20
|
+
|
21
|
+
from .base import (
|
22
|
+
BaseSQLDB,
|
23
|
+
SQLDBUnavailableError,
|
24
|
+
_get_columns,
|
25
|
+
apply_search_filters,
|
26
|
+
apply_sort_constraints,
|
27
|
+
uuid7_from_datetime,
|
28
|
+
uuid7_to_datetime,
|
27
29
|
)
|
30
|
+
from .functions import hash, substract_date, utcnow
|
31
|
+
from .types import Column, DateNowColumn, EnumBackedBool, EnumColumn, NullColumn
|
@@ -7,13 +7,15 @@ import re
|
|
7
7
|
from abc import ABCMeta
|
8
8
|
from collections.abc import AsyncIterator
|
9
9
|
from contextvars import ContextVar
|
10
|
-
from datetime import datetime
|
10
|
+
from datetime import datetime, timezone
|
11
11
|
from typing import Any, Self, cast
|
12
|
+
from uuid import UUID as StdUUID # noqa: N811
|
12
13
|
|
13
14
|
from pydantic import TypeAdapter
|
14
15
|
from sqlalchemy import DateTime, MetaData, func, select
|
15
16
|
from sqlalchemy.exc import OperationalError
|
16
17
|
from sqlalchemy.ext.asyncio import AsyncConnection, AsyncEngine, create_async_engine
|
18
|
+
from uuid_utils import UUID, uuid7
|
17
19
|
|
18
20
|
from diracx.core.exceptions import InvalidQueryError
|
19
21
|
from diracx.core.extensions import select_from_extension
|
@@ -416,3 +418,33 @@ def apply_sort_constraints(column_mapping, stmt, sorts):
|
|
416
418
|
if sort_columns:
|
417
419
|
stmt = stmt.order_by(*sort_columns)
|
418
420
|
return stmt
|
421
|
+
|
422
|
+
|
423
|
+
def uuid7_to_datetime(uuid: UUID | StdUUID | str) -> datetime:
|
424
|
+
"""Convert a UUIDv7 to a datetime."""
|
425
|
+
if isinstance(uuid, StdUUID):
|
426
|
+
# Convert stdlib UUID to uuid_utils.UUID
|
427
|
+
uuid = UUID(str(uuid))
|
428
|
+
elif not isinstance(uuid, UUID):
|
429
|
+
# Convert string or other types to uuid_utils.UUID
|
430
|
+
uuid = UUID(uuid)
|
431
|
+
if uuid.version != 7:
|
432
|
+
raise ValueError(f"UUID {uuid} is not a UUIDv7")
|
433
|
+
return datetime.fromtimestamp(uuid.timestamp / 1000.0, tz=timezone.utc)
|
434
|
+
|
435
|
+
|
436
|
+
def uuid7_from_datetime(dt: datetime, *, randomize: bool = True) -> UUID:
|
437
|
+
"""Generate a UUIDv7 corresponding to the given datetime.
|
438
|
+
|
439
|
+
If randomize is True, the standard uuid7 function is used resulting in the
|
440
|
+
lowest 62-bits being random. If randomize is False, the UUIDv7 will be the
|
441
|
+
lowest possible UUIDv7 for the given datetime.
|
442
|
+
"""
|
443
|
+
timestamp = dt.timestamp()
|
444
|
+
if randomize:
|
445
|
+
uuid = uuid7(int(timestamp), int((timestamp % 1) * 1e9))
|
446
|
+
else:
|
447
|
+
time_high = int(timestamp * 1000) >> 16
|
448
|
+
time_low = int(timestamp * 1000) & 0xFFFF
|
449
|
+
uuid = UUID.from_fields((time_high, time_low, 0x7000, 0x80, 0, 0))
|
450
|
+
return uuid
|
@@ -56,7 +56,6 @@ async def test_get(auth_db: AuthDB):
|
|
56
56
|
refresh_token_details["sub"],
|
57
57
|
refresh_token_details["scope"],
|
58
58
|
)
|
59
|
-
creation_time = (await auth_db.get_refresh_token(jti))["CreationTime"]
|
60
59
|
|
61
60
|
# Enrich the dict with the generated refresh token attributes
|
62
61
|
expected_refresh_token = {
|
@@ -64,7 +63,6 @@ async def test_get(auth_db: AuthDB):
|
|
64
63
|
"Scope": refresh_token_details["scope"],
|
65
64
|
"JTI": jti,
|
66
65
|
"Status": RefreshTokenStatus.CREATED,
|
67
|
-
"CreationTime": creation_time,
|
68
66
|
}
|
69
67
|
|
70
68
|
# Get refresh token details
|
@@ -0,0 +1,221 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from datetime import datetime, timedelta, timezone
|
4
|
+
from uuid import UUID as StdUUID # noqa: N811
|
5
|
+
|
6
|
+
import freezegun
|
7
|
+
import pytest
|
8
|
+
from uuid_utils import UUID, uuid7
|
9
|
+
|
10
|
+
from diracx.db.sql.utils import uuid7_from_datetime, uuid7_to_datetime
|
11
|
+
|
12
|
+
|
13
|
+
def frozen_uuid7() -> UUID:
|
14
|
+
"""Create a UUID7 in a way which respects the freezegun context."""
|
15
|
+
timestamp = datetime.now(tz=timezone.utc).timestamp()
|
16
|
+
return uuid7(int(timestamp), int((timestamp % 1) * 1e9))
|
17
|
+
|
18
|
+
|
19
|
+
class TestDatetimeToUuid7:
|
20
|
+
"""Test cases for the datetime_to_uuid7 function."""
|
21
|
+
|
22
|
+
def test_datetime_to_uuid7_random(self):
|
23
|
+
"""Test that the datetime_to_uuid7 function returns a UUID7 with the current timestamp."""
|
24
|
+
dt = datetime.fromisoformat("2024-01-15T12:30:45.123456+00:00")
|
25
|
+
result = uuid7_from_datetime(dt, randomize=True)
|
26
|
+
assert str(result)[:15] == "018d0d1a-5183-7"
|
27
|
+
assert len(set(str(result)[15:])) > 4
|
28
|
+
|
29
|
+
def test_datetime_to_uuid7_deterministic(self):
|
30
|
+
"""Test that the datetime_to_uuid7 function returns a UUID7 with the current timestamp."""
|
31
|
+
dt = datetime.fromisoformat("2024-01-15T12:30:45.123456+00:00")
|
32
|
+
result = uuid7_from_datetime(dt, randomize=False)
|
33
|
+
assert str(result) == "018d0d1a-5183-7000-8000-000000000000"
|
34
|
+
|
35
|
+
|
36
|
+
class TestUuid7ToDatetime:
|
37
|
+
"""Test cases for the uuid7_to_datetime function."""
|
38
|
+
|
39
|
+
def test_uuid7_now(self):
|
40
|
+
"""Test that the uuid7 function returns a UUID7 with the current timestamp."""
|
41
|
+
test_uuid = frozen_uuid7()
|
42
|
+
result = uuid7_to_datetime(test_uuid)
|
43
|
+
assert result.tzinfo == timezone.utc
|
44
|
+
assert result - datetime.now(tz=timezone.utc) < timedelta(milliseconds=2)
|
45
|
+
|
46
|
+
@freezegun.freeze_time("2024-01-15 12:30:45.123456")
|
47
|
+
def test_uuid7_to_datetime_with_uuid_utils_uuid(self):
|
48
|
+
"""Test conversion with uuid_utils.UUID object."""
|
49
|
+
test_uuid = frozen_uuid7()
|
50
|
+
result = uuid7_to_datetime(test_uuid)
|
51
|
+
|
52
|
+
assert isinstance(result, datetime)
|
53
|
+
assert result.tzinfo == timezone.utc
|
54
|
+
assert result.isoformat() == "2024-01-15T12:30:45.123000+00:00"
|
55
|
+
|
56
|
+
@freezegun.freeze_time("2024-01-15 12:30:45.123456")
|
57
|
+
def test_uuid7_to_datetime_with_stdlib_uuid(self):
|
58
|
+
"""Test conversion with standard library UUID object."""
|
59
|
+
test_uuid = frozen_uuid7()
|
60
|
+
stdlib_uuid = StdUUID(str(test_uuid))
|
61
|
+
|
62
|
+
result = uuid7_to_datetime(stdlib_uuid)
|
63
|
+
assert isinstance(result, datetime)
|
64
|
+
assert result.tzinfo == timezone.utc
|
65
|
+
|
66
|
+
@freezegun.freeze_time("2024-01-15 12:30:45.123456")
|
67
|
+
def test_uuid7_to_datetime_with_string_uuid(self):
|
68
|
+
"""Test conversion with string UUID that gets converted to uuid_utils.UUID."""
|
69
|
+
test_uuid = frozen_uuid7()
|
70
|
+
uuid_string = str(test_uuid)
|
71
|
+
|
72
|
+
result = uuid7_to_datetime(uuid_string)
|
73
|
+
assert isinstance(result, datetime)
|
74
|
+
assert result.tzinfo == timezone.utc
|
75
|
+
|
76
|
+
@freezegun.freeze_time("2024-01-15 12:30:45.123456")
|
77
|
+
def test_uuid7_to_datetime_precision(self):
|
78
|
+
"""Test that the conversion maintains reasonable precision."""
|
79
|
+
test_uuid = frozen_uuid7()
|
80
|
+
result = uuid7_to_datetime(test_uuid)
|
81
|
+
|
82
|
+
assert isinstance(result, datetime)
|
83
|
+
assert result.tzinfo == timezone.utc
|
84
|
+
assert result.isoformat() == "2024-01-15T12:30:45.123000+00:00"
|
85
|
+
|
86
|
+
@freezegun.freeze_time("1970-01-01 00:00:00.000000")
|
87
|
+
def test_uuid7_to_datetime_epoch_boundary(self):
|
88
|
+
"""Test conversion with UUID7 at epoch boundary."""
|
89
|
+
test_uuid = frozen_uuid7()
|
90
|
+
result = uuid7_to_datetime(test_uuid)
|
91
|
+
|
92
|
+
assert isinstance(result, datetime)
|
93
|
+
assert result.tzinfo == timezone.utc
|
94
|
+
assert result.isoformat() == "1970-01-01T00:00:00+00:00"
|
95
|
+
|
96
|
+
@freezegun.freeze_time("2100-01-01 00:00:00.000000")
|
97
|
+
def test_uuid7_to_datetime_future_timestamp(self):
|
98
|
+
"""Test conversion with future timestamp."""
|
99
|
+
test_uuid = frozen_uuid7()
|
100
|
+
result = uuid7_to_datetime(test_uuid)
|
101
|
+
|
102
|
+
assert isinstance(result, datetime)
|
103
|
+
assert result.tzinfo == timezone.utc
|
104
|
+
assert result.isoformat() == "2100-01-01T00:00:00+00:00"
|
105
|
+
|
106
|
+
@freezegun.freeze_time("2024-01-15 12:30:45.123456")
|
107
|
+
def test_uuid7_to_datetime_consistency(self):
|
108
|
+
"""Test that multiple calls with the same UUID return the same result."""
|
109
|
+
test_uuid = frozen_uuid7()
|
110
|
+
|
111
|
+
result1 = uuid7_to_datetime(test_uuid)
|
112
|
+
result2 = uuid7_to_datetime(test_uuid)
|
113
|
+
|
114
|
+
assert result1.isoformat() == result2.isoformat()
|
115
|
+
assert result1 == result2
|
116
|
+
|
117
|
+
@freezegun.freeze_time("2024-01-15 12:30:45.123456")
|
118
|
+
def test_uuid7_to_datetime_different_input_types_same_result(self):
|
119
|
+
"""Test that different input types representing the same UUID return the same result."""
|
120
|
+
test_uuid = frozen_uuid7()
|
121
|
+
uuid_string = str(test_uuid)
|
122
|
+
stdlib_uuid = StdUUID(uuid_string)
|
123
|
+
|
124
|
+
result_from_uuid_utils = uuid7_to_datetime(test_uuid)
|
125
|
+
result_from_string = uuid7_to_datetime(uuid_string)
|
126
|
+
result_from_stdlib = uuid7_to_datetime(stdlib_uuid)
|
127
|
+
|
128
|
+
# All results should be identical
|
129
|
+
assert result_from_uuid_utils == result_from_string == result_from_stdlib
|
130
|
+
|
131
|
+
def test_uuid7_to_datetime_invalid_input_type(self):
|
132
|
+
"""Test that invalid input types raise appropriate errors."""
|
133
|
+
with pytest.raises(TypeError):
|
134
|
+
uuid7_to_datetime(123) # type: ignore
|
135
|
+
|
136
|
+
with pytest.raises(TypeError):
|
137
|
+
uuid7_to_datetime(123.45) # type: ignore
|
138
|
+
|
139
|
+
with pytest.raises(TypeError):
|
140
|
+
uuid7_to_datetime([]) # type: ignore
|
141
|
+
|
142
|
+
with pytest.raises(TypeError):
|
143
|
+
uuid7_to_datetime({}) # type: ignore
|
144
|
+
|
145
|
+
def test_uuid7_to_datetime_invalid_uuid_string(self):
|
146
|
+
"""Test that invalid UUID strings raise appropriate errors."""
|
147
|
+
with pytest.raises(ValueError):
|
148
|
+
uuid7_to_datetime("not-a-uuid")
|
149
|
+
|
150
|
+
with pytest.raises(ValueError):
|
151
|
+
uuid7_to_datetime("12345")
|
152
|
+
|
153
|
+
with pytest.raises(ValueError):
|
154
|
+
uuid7_to_datetime("")
|
155
|
+
|
156
|
+
def test_uuid7_to_datetime_non_uuid7_uuid(self):
|
157
|
+
"""Test behavior with non-UUID7 UUIDs."""
|
158
|
+
uuid4 = StdUUID("550e8400-e29b-41d4-a716-446655440000")
|
159
|
+
|
160
|
+
with pytest.raises(ValueError, match="is not a UUIDv7"):
|
161
|
+
uuid7_to_datetime(uuid4)
|
162
|
+
|
163
|
+
@freezegun.freeze_time("2024-01-15 12:30:45.123456")
|
164
|
+
def test_uuid7_to_datetime_timezone_awareness(self):
|
165
|
+
"""Test that the returned datetime is always timezone-aware and in UTC."""
|
166
|
+
test_uuid = frozen_uuid7()
|
167
|
+
result = uuid7_to_datetime(test_uuid)
|
168
|
+
|
169
|
+
assert result.tzinfo is not None
|
170
|
+
|
171
|
+
assert result.tzinfo == timezone.utc
|
172
|
+
|
173
|
+
assert result.tzinfo.utcoffset(result) is not None
|
174
|
+
|
175
|
+
@freezegun.freeze_time("2024-01-15 12:30:45.123456")
|
176
|
+
def test_uuid7_to_datetime_millisecond_precision(self):
|
177
|
+
"""Test that the conversion handles millisecond precision correctly."""
|
178
|
+
uuids = [frozen_uuid7() for _ in range(5)]
|
179
|
+
results = [uuid7_to_datetime(uuid) for uuid in uuids]
|
180
|
+
|
181
|
+
for result in results:
|
182
|
+
assert isinstance(result, datetime)
|
183
|
+
assert result.tzinfo == timezone.utc
|
184
|
+
|
185
|
+
timestamps = [r.timestamp() for r in results]
|
186
|
+
assert timestamps == sorted(timestamps)
|
187
|
+
|
188
|
+
@freezegun.freeze_time("2024-01-15 12:30:45.123456")
|
189
|
+
def test_uuid7_to_datetime_timestamp_property(self):
|
190
|
+
"""Test that the function correctly uses the timestamp property."""
|
191
|
+
test_uuid = frozen_uuid7()
|
192
|
+
result = uuid7_to_datetime(test_uuid)
|
193
|
+
|
194
|
+
expected_timestamp = test_uuid.timestamp / 1000.0
|
195
|
+
actual_timestamp = result.timestamp()
|
196
|
+
|
197
|
+
assert abs(actual_timestamp - expected_timestamp) < 0.001
|
198
|
+
|
199
|
+
@freezegun.freeze_time("2024-01-15 12:30:45.123456")
|
200
|
+
def test_uuid7_to_datetime_deterministic_with_freeze(self):
|
201
|
+
"""Test that the function works deterministically with freezegun."""
|
202
|
+
with freezegun.freeze_time("2024-01-15 12:30:45.123000"):
|
203
|
+
uuid1 = frozen_uuid7()
|
204
|
+
result1 = uuid7_to_datetime(uuid1)
|
205
|
+
|
206
|
+
with freezegun.freeze_time("2024-01-15 12:30:45.123000"):
|
207
|
+
uuid2 = frozen_uuid7()
|
208
|
+
result2 = uuid7_to_datetime(uuid2)
|
209
|
+
|
210
|
+
time_diff = abs((result1 - result2).total_seconds())
|
211
|
+
assert time_diff < 1.0
|
212
|
+
|
213
|
+
@freezegun.freeze_time("1970-01-01 00:00:00")
|
214
|
+
def test_uuid7_to_datetime_edge_case_zero_timestamp(self):
|
215
|
+
"""Test edge case with very small timestamp values."""
|
216
|
+
test_uuid = frozen_uuid7()
|
217
|
+
result = uuid7_to_datetime(test_uuid)
|
218
|
+
|
219
|
+
assert isinstance(result, datetime)
|
220
|
+
assert result.tzinfo == timezone.utc
|
221
|
+
assert result.isoformat() == "1970-01-01T00:00:00+00:00"
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|