1from __future__ import annotations
2
3import base64
4import typing as t
5
6import typing_extensions as te
7from pydantic import BaseModel, BeforeValidator, ConfigDict, PlainSerializer
8from pydantic.alias_generators import to_camel
9
10
11class Base(BaseModel):
12 model_config = ConfigDict(
13 alias_generator=to_camel,
14 strict=True,
15 extra="forbid",
16 validate_by_name=True,
17 validate_by_alias=True,
18 )
19
20 @classmethod
21 def from_json(cls, json: str | bytes) -> te.Self:
22 return cls.model_validate_json(json)
23
24 @classmethod
25 def from_dict(cls, data: dict) -> te.Self:
26 return cls.model_validate(data)
27
28 def to_json(self) -> str:
29 return self.model_dump_json(
30 exclude_none=True,
31 exclude_unset=True,
32 by_alias=True,
33 )
34
35 def to_dict(self) -> dict:
36 return self.model_dump(
37 mode="json", exclude_none=True, exclude_unset=True, by_alias=True
38 )
39
40
41def _validate_proto_u64(value: object) -> int:
42 if not isinstance(value, str):
43 raise ValueError(
44 f"Expected protobuf uint64 as string, got {type(value).__name__}"
45 )
46
47 n = int(value)
48 if n < 0 or n > 2**64 - 1:
49 raise ValueError(f"Value exceeds uint64 domain: {value}")
50
51 return n
52
53
54def _serialize_proto_u64(value: int) -> str:
55 if value < 0 or value > 2**64 - 1:
56 raise ValueError(f"Value exceeds uint64 domain: {value}")
57
58 return str(value)
59
60
61ProtoU64 = t.Annotated[
62 int,
63 BeforeValidator(_validate_proto_u64),
64 PlainSerializer(_serialize_proto_u64, return_type=str),
65]
66
67
68def _validate_proto_bytes(value: object) -> bytes:
69 if not isinstance(value, (bytes, str)):
70 raise ValueError(
71 f"Expected protobuf bytes as string or bytes, got {type(value).__name__}"
72 )
73
74 return base64.b64decode(value)
75
76
77def _serialize_proto_bytes(value: bytes) -> bytes:
78 return base64.b64encode(value)
79
80
81ProtoBytes = t.Annotated[
82 bytes,
83 BeforeValidator(_validate_proto_bytes),
84 PlainSerializer(_serialize_proto_bytes, return_type=bytes),
85]