2025-02-05 14:02:36 +01:00
|
|
|
from datetime import datetime, timezone
|
|
|
|
from typing import Any
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
from pydantic import BaseModel, ValidationError
|
|
|
|
|
|
|
|
from pydantic_extra_types.ulid import ULID
|
|
|
|
|
|
|
|
try:
|
|
|
|
from ulid import ULID as _ULID
|
|
|
|
except ModuleNotFoundError: # pragma: no cover
|
|
|
|
raise RuntimeError(
|
|
|
|
'The `ulid` module requires "python-ulid" to be installed. You can install it with "pip install python-ulid".'
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class Something(BaseModel):
|
|
|
|
ulid: ULID
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
'ulid, result, valid',
|
|
|
|
[
|
|
|
|
# Valid ULID for str format
|
|
|
|
('01BTGNYV6HRNK8K8VKZASZCFPE', '01BTGNYV6HRNK8K8VKZASZCFPE', True),
|
|
|
|
('01BTGNYV6HRNK8K8VKZASZCFPF', '01BTGNYV6HRNK8K8VKZASZCFPF', True),
|
|
|
|
# Invalid ULID for str format
|
|
|
|
('01BTGNYV6HRNK8K8VKZASZCFP', None, False), # Invalid ULID (short length)
|
|
|
|
('01BTGNYV6HRNK8K8VKZASZCFPEA', None, False), # Invalid ULID (long length)
|
|
|
|
# Valid ULID for _ULID format
|
|
|
|
(_ULID.from_str('01BTGNYV6HRNK8K8VKZASZCFPE'), '01BTGNYV6HRNK8K8VKZASZCFPE', True),
|
|
|
|
(_ULID.from_str('01BTGNYV6HRNK8K8VKZASZCFPF'), '01BTGNYV6HRNK8K8VKZASZCFPF', True),
|
|
|
|
# Invalid _ULID for bytes format
|
2025-02-05 14:03:42 +01:00
|
|
|
(b'\x01\xba\x1e\xb2\x8a\x9f\xfay\x10\xd5\xa5k\xc8', None, False), # Invalid ULID (short length)
|
|
|
|
(b'\x01\xba\x1e\xb2\x8a\x9f\xfay\x10\xd5\xa5k\xc8\xb6\x00', None, False), # Invalid ULID (long length)
|
2025-02-05 14:02:36 +01:00
|
|
|
# Valid ULID for int format
|
|
|
|
(109667145845879622871206540411193812282, '2JG4FVY7N8XS4GFVHPXGJZ8S9T', True),
|
|
|
|
(109667145845879622871206540411193812283, '2JG4FVY7N8XS4GFVHPXGJZ8S9V', True),
|
|
|
|
(109667145845879622871206540411193812284, '2JG4FVY7N8XS4GFVHPXGJZ8S9W', True),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
def test_format_for_ulid(ulid: Any, result: Any, valid: bool):
|
|
|
|
if valid:
|
|
|
|
assert str(Something(ulid=ulid).ulid) == result
|
|
|
|
else:
|
|
|
|
with pytest.raises(ValidationError, match='format'):
|
|
|
|
Something(ulid=ulid)
|
|
|
|
|
|
|
|
|
|
|
|
def test_property_for_ulid():
|
|
|
|
ulid = Something(ulid='01BTGNYV6HRNK8K8VKZASZCFPE').ulid
|
|
|
|
assert ulid.hex == '015ea15f6cd1c56689a373fab3f63ece'
|
|
|
|
assert ulid == '01BTGNYV6HRNK8K8VKZASZCFPE'
|
|
|
|
assert ulid.datetime == datetime(2017, 9, 20, 22, 18, 59, 153000, tzinfo=timezone.utc)
|
|
|
|
assert ulid.timestamp == 1505945939.153
|
|
|
|
|
|
|
|
|
|
|
|
def test_json_schema():
|
|
|
|
assert Something.model_json_schema(mode='validation') == {
|
|
|
|
'properties': {
|
|
|
|
'ulid': {
|
|
|
|
'anyOf': [{'type': 'integer'}, {'format': 'binary', 'type': 'string'}, {'type': 'string'}],
|
|
|
|
'title': 'Ulid',
|
|
|
|
}
|
|
|
|
},
|
|
|
|
'required': ['ulid'],
|
|
|
|
'title': 'Something',
|
|
|
|
'type': 'object',
|
|
|
|
}
|
|
|
|
assert Something.model_json_schema(mode='serialization') == {
|
|
|
|
'properties': {
|
|
|
|
'ulid': {
|
|
|
|
'anyOf': [{'type': 'integer'}, {'format': 'binary', 'type': 'string'}, {'type': 'string'}],
|
|
|
|
'title': 'Ulid',
|
|
|
|
}
|
|
|
|
},
|
|
|
|
'required': ['ulid'],
|
|
|
|
'title': 'Something',
|
|
|
|
'type': 'object',
|
|
|
|
}
|