1+ import base64
12import re
3+ from typing import Annotated
4+ from typing import Literal
25from typing import Optional
36from typing import Union
47
8+ from pydantic import EncodedBytes
9+ from pydantic import EncoderProtocol
510from pydantic .alias_generators import to_snake
11+ from pydantic_core import PydanticCustomError
612
713try :
814 from types import UnionType # type: ignore
@@ -17,6 +23,57 @@ def int_to_str(status: Optional[int]) -> Optional[str]:
1723 return None if status is None else str (status )
1824
1925
26+ # Copied from Pydantic 2.10 repository
27+ class Base64Encoder (EncoderProtocol ): # pragma: no cover
28+ """Standard (non-URL-safe) Base64 encoder."""
29+
30+ @classmethod
31+ def decode (cls , data : bytes ) -> bytes :
32+ """Decode the data from base64 encoded bytes to original bytes data.
33+
34+ Args:
35+ data: The data to decode.
36+
37+ Returns:
38+ The decoded data.
39+
40+ """
41+ try :
42+ return base64 .b64decode (data )
43+ except ValueError as e :
44+ raise PydanticCustomError (
45+ "base64_decode" , "Base64 decoding error: '{error}'" , {"error" : str (e )}
46+ ) from e
47+
48+ @classmethod
49+ def encode (cls , value : bytes ) -> bytes :
50+ """Encode the data from bytes to a base64 encoded bytes.
51+
52+ Args:
53+ value: The data to encode.
54+
55+ Returns:
56+ The encoded data.
57+
58+ """
59+ return base64 .b64encode (value )
60+
61+ @classmethod
62+ def get_json_format (cls ) -> Literal ["base64" ]:
63+ """Get the JSON format for the encoded data.
64+
65+ Returns:
66+ The JSON format for the encoded data.
67+
68+ """
69+ return "base64"
70+
71+
72+ # Compatibility with Pydantic <2.10
73+ # https://pydantic.dev/articles/pydantic-v2-10-release#use-b64decode-and-b64encode-for-base64bytes-and-base64str-types
74+ Base64Bytes = Annotated [bytes , EncodedBytes (encoder = Base64Encoder )]
75+
76+
2077def to_camel (string : str ) -> str :
2178 """Transform strings to camelCase.
2279
0 commit comments