Skip to content

Commit aa280c6

Browse files
committed
epoch - split into number & integer
1 parent 6cd0de0 commit aa280c6

File tree

2 files changed

+32
-13
lines changed

2 files changed

+32
-13
lines changed

pydantic_extra_types/epoch.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,53 @@
11
import datetime
2-
from typing import Any, Callable
2+
from typing import Any, Callable, Optional
33

4+
import pydantic_core.core_schema
45
from pydantic import GetJsonSchemaHandler
56
from pydantic.json_schema import JsonSchemaValue
67
from pydantic_core import CoreSchema, core_schema
78

89
EPOCH = datetime.datetime(1970, 1, 1, tzinfo=datetime.timezone.utc)
910

1011

11-
class Epoch(datetime.datetime):
12+
class _Base(datetime.datetime):
13+
TYPE: str = ''
14+
CLS: Optional[Callable[[Any], Any]]
15+
SCHEMA: pydantic_core.core_schema.CoreSchema
16+
1217
@classmethod
1318
def __get_pydantic_json_schema__(
1419
cls, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
1520
) -> JsonSchemaValue:
1621
field_schema: dict[str, Any] = {}
17-
field_schema.update(type='number', format='date-time')
22+
field_schema.update(type=cls.TYPE, format='date-time')
1823
return field_schema
1924

2025
@classmethod
2126
def __get_pydantic_core_schema__(
2227
cls, source: type[Any], handler: Callable[[Any], CoreSchema]
2328
) -> core_schema.CoreSchema:
2429
def f(value: Any, serializer: Callable[[datetime.datetime], float]) -> float:
25-
return serializer(value.timestamp())
30+
ts = value.timestamp()
31+
return serializer(cls.CLS(ts) if cls.CLS is not None else ts)
2632

2733
return core_schema.with_info_after_validator_function(
2834
cls._validate,
29-
core_schema.float_schema(),
30-
serialization=core_schema.wrap_serializer_function_ser_schema(f, return_schema=core_schema.float_schema()),
35+
cls.SCHEMA,
36+
serialization=core_schema.wrap_serializer_function_ser_schema(f, return_schema=cls.SCHEMA),
3137
)
3238

3339
@classmethod
3440
def _validate(cls, __input_value: Any, _: Any) -> datetime.datetime:
3541
return EPOCH + datetime.timedelta(seconds=__input_value)
42+
43+
44+
class Number(_Base):
45+
TYPE = 'number'
46+
CLS = None
47+
SCHEMA = core_schema.float_schema()
48+
49+
50+
class Integer(_Base):
51+
TYPE = 'integer'
52+
CLS = int
53+
SCHEMA = core_schema.int_schema()

tests/test_epoch.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22

33
import pytest
44

5-
from pydantic_extra_types.epoch import Epoch
5+
from pydantic_extra_types import epoch
66

77

8-
@pytest.mark.parametrize('type_', [(int,), (float,)], ids=['integer', 'float'])
9-
def test_type(type_):
8+
@pytest.mark.parametrize('type_,cls_', [(int, epoch.Integer), (float, epoch.Number)], ids=['integer', 'number'])
9+
def test_type(type_, cls_):
1010
from pydantic import BaseModel
1111

1212
class A(BaseModel):
13-
epoch: Epoch
13+
epoch: cls_
1414

1515
now = datetime.datetime.now(tz=datetime.timezone.utc)
1616
ts = type_(now.timestamp())
@@ -28,11 +28,12 @@ class A(BaseModel):
2828
assert v['epoch'] == ts
2929

3030

31-
def test_schema():
31+
@pytest.mark.parametrize('cls_', [(epoch.Integer), (epoch.Number)], ids=['integer', 'number'])
32+
def test_schema(cls_):
3233
from pydantic import BaseModel
3334

3435
class A(BaseModel):
35-
dt: Epoch
36+
dt: cls_
3637

3738
v = A.model_json_schema()
38-
assert (dt := v['properties']['dt'])['type'] == 'number' and dt['format'] == 'date-time'
39+
assert (dt := v['properties']['dt'])['type'] == cls_.TYPE and dt['format'] == 'date-time'

0 commit comments

Comments
 (0)