18 from typing
import Any, Optional, Type, Dict, Tuple
19 from typing_extensions
import Self
20 from datetime
import datetime
26 from .descriptor
import KeyDescriptor
27 from ..utils.date
import DATE_FORMAT, decodeDate
33 Class whose subclasses can be serialized/deserialized into/from a JSON format object
37 def _keyDescriptors(cls) -> Dict[str, KeyDescriptor]:
39 Defines a custom mapping for python objects to json field
40 Key of the dictionary represents a name of the field in python
41 Value of the dictionary represents how should the object be serialized/deserialized
45 Dict[str, KeyDescriptor] -> Dictionary of objects describing translation
51 def __keyDescriptorByJsonName(cls, jsonName: str) -> Tuple[Optional[str], Optional[KeyDescriptor]]:
53 if value.jsonName == jsonName:
59 def __keyDescriptorByPythonName(cls, pythonName: str) -> Optional[KeyDescriptor]:
67 def __encodeKey(self, key: str) -> str:
68 descriptor = self.__class__.__keyDescriptorByPythonName(key)
70 if descriptor
is None or descriptor.jsonName
is None:
71 return inflection.underscore(key)
73 return descriptor.jsonName
75 def _encodeValue(self, key: str, value: Any) -> Any:
77 Encodes python value into a json property
78 Custom field serialization can be implemented by overriding this method
83 python object variable name
85 json object represented as an object from standard python library
89 Any -> encoded value of the object
92 descriptor = self.__class__.__keyDescriptorByPythonName(key)
94 if descriptor
is None or descriptor.pythonType
is None:
97 if issubclass(descriptor.pythonType, Enum):
98 if descriptor.isList():
99 return [element.value
for element
in value]
103 if issubclass(descriptor.pythonType, UUID):
104 if descriptor.isList():
105 return [str(element)
for element
in value]
109 if issubclass(descriptor.pythonType, Codable):
110 if descriptor.isList():
111 return [descriptor.pythonType.encode(element)
for element
in value]
113 return descriptor.pythonType.encode(value)
115 if issubclass(descriptor.pythonType, datetime):
116 if descriptor.isList():
117 return [element.strftime(DATE_FORMAT)
for element
in value]
119 return value.strftime(DATE_FORMAT)
125 Encodes python object into dictionary which contains
126 only values representable by standard python library/types
130 Dict[str, Any] -> encoded object which can be serialized into json string
133 encodedObject: Dict[str, Any] = {}
135 for key, value
in self.__dict__.items():
136 descriptor = self.__class__.__keyDescriptorByPythonName(key)
139 if descriptor
is not None and not descriptor.isEncodable:
144 encodedValue = self.
_encodeValue_encodeValue(key, value)
146 encodedObject[encodedKey] = encodedValue
153 def __decodeKey(cls, key: str) -> str:
156 if descriptorKey
is None:
157 return inflection.camelize(key,
False)
162 def _decodeValue(cls, key: str, value: Any) -> Any:
164 Decodes a value of a single json field
165 Custom logic can be implemented by overriding this method
170 name of the json field
172 value of the json field
176 Any -> decoded value of the json field
181 if descriptor
is None or descriptor.pythonType
is None:
184 if issubclass(descriptor.pythonType, Enum):
185 if descriptor.isList()
and descriptor.collectionType
is not None:
186 return descriptor.collectionType([descriptor.pythonType(element)
for element
in value])
188 return descriptor.pythonType(value)
190 if issubclass(descriptor.pythonType, UUID):
191 if descriptor.isList()
and descriptor.collectionType
is not None:
192 return descriptor.collectionType([descriptor.pythonType(element)
for element
in value])
194 return descriptor.pythonType(value)
196 if issubclass(descriptor.pythonType, Codable):
197 if descriptor.isList()
and descriptor.collectionType
is not None:
198 return descriptor.collectionType([descriptor.pythonType.decode(element)
for element
in value])
200 return descriptor.pythonType.decode(value)
202 if issubclass(descriptor.pythonType, datetime):
203 if descriptor.isList()
and descriptor.collectionType
is not None:
204 return descriptor.collectionType([decodeDate(element)
for element
in value])
206 return decodeDate(value)
210 def _updateFields(self, encodedObject: Dict[str, Any]) ->
None:
212 Updates the properties of object with new values
216 encodedObject : Dict[str, Any]
220 for key, value
in encodedObject.items():
221 _, descriptor = self.__class__.__keyDescriptorByJsonName(key)
224 if descriptor
is not None and not descriptor.isDecodable:
229 self.__dict__[decodedKey] = self.
_decodeValue_decodeValue(key, value)
233 Callback which is called once the object has been decoded
239 def decode(cls, encodedObject: Dict[str, Any]) -> Self:
241 Decodes the json object into a python object
245 encodedObject : Dict[str, Any]
250 Self -> Decoded python object
254 obj._updateFields(encodedObject)
Dict[str, KeyDescriptor] _keyDescriptors(cls)
Dict[str, Any] encode(self)
Any _encodeValue(self, str key, Any value)
str __decodeKey(cls, str key)
Self decode(cls, Dict[str, Any] encodedObject)
Tuple[Optional[str], Optional[KeyDescriptor]] __keyDescriptorByJsonName(cls, str jsonName)
Any _decodeValue(cls, str key, Any value)
str __encodeKey(self, str key)