@@ -60,15 +60,19 @@ def serialize(self, obj):
6060 # type: (Any) -> Union[Dict[str, Any], List, Tuple, str, None]
6161 """Builds a serialized object.
6262
63- If obj is None, return None.
64- If obj is str, int, long, float, bool, return directly.
65- If obj is datetime.datetime, datetime.date convert to
66- string in iso8601 format.
67- If obj is list, serialize each element in the list.
68- If obj is dict, return the dict with serialized values.
69- If obj is ask sdk model, return the dict with keys resolved
70- from model's ``attribute_map`` and values serialized
71- based on ``deserialized_types``.
63+ * If obj is None, return None.
64+ * If obj is str, int, long, float, bool, return directly.
65+ * If obj is datetime.datetime, datetime.date convert to
66+ string in iso8601 format.
67+ * If obj is list, serialize each element in the list.
68+ * If obj is dict, return the dict with serialized values.
69+ * If obj is ask sdk model, return the dict with keys resolved
70+ from the union of model's ``attribute_map`` and
71+ ``deserialized_types`` and values serialized based on
72+ ``deserialized_types``.
73+ * If obj is a generic class instance, return the dict with keys
74+ from instance's ``deserialized_types`` and values serialized
75+ based on ``deserialized_types``.
7276
7377 :param obj: The data to serialize.
7478 :type obj: object
@@ -96,13 +100,22 @@ def serialize(self, obj):
96100 if isinstance (obj , dict ):
97101 obj_dict = obj
98102 else :
99- # Convert model obj to dict except
100- # attributes `deserialized_types`, `attribute_map`
101- # and attributes which value is not None.
102- # Convert attribute name to json key in
103- # model definition for request.
103+ # Convert model obj to dict
104+ # All the non null attributes under `deserialized_types`
105+ # map are considered for serialization.
106+ # The `attribute_map` provides the key names to be used
107+ # in the dict. In case of missing `attribute_map` mapping,
108+ # the original attribute name is retained as the key name.
109+ class_attribute_map = getattr (obj , 'attribute_map' , {})
110+ class_attribute_map .update (
111+ {
112+ k : k for k in obj .deserialized_types .keys ()
113+ if k not in class_attribute_map
114+ }
115+ )
116+
104117 obj_dict = {
105- obj . attribute_map [attr ]: getattr (obj , attr )
118+ class_attribute_map [attr ]: getattr (obj , attr )
106119 for attr , _ in iteritems (obj .deserialized_types )
107120 if getattr (obj , attr ) is not None
108121 }
@@ -111,7 +124,28 @@ def serialize(self, obj):
111124
112125 def deserialize (self , payload , obj_type ):
113126 # type: (str, Union[T, str]) -> Any
114- """Deserializes payload into ask sdk model object.
127+ """Deserializes payload into an instance of provided ``obj_type``.
128+
129+ The ``obj_type`` parameter can be a primitive type, a generic
130+ model object or a list / dict of model objects.
131+
132+ The list or dict object type has to be provided as a string
133+ format. For eg:
134+
135+ * ``'list[a.b.C]'`` if the payload is a list of instances of
136+ class ``a.b.C``.
137+ * ``'dict(str, a.b.C)'`` if the payload is a dict containing
138+ mappings of ``str : a.b.C`` class instance types.
139+
140+ The method looks for a ``deserialized_types`` dict in the model
141+ class, that mentions which payload values has to be
142+ deserialized. In case the payload key names are different than
143+ the model attribute names, the corresponding mapping can be
144+ provided in another special dict ``attribute_map``. The model
145+ class should also have the ``__init__`` method with default
146+ values for arguments. Check
147+ :py:class:`ask_sdk_model.request_envelope.RequestEnvelope`
148+ source code for an example implementation.
115149
116150 :param payload: data to be deserialized.
117151 :type payload: str
@@ -134,14 +168,14 @@ def deserialize(self, payload, obj_type):
134168
135169 def __deserialize (self , payload , obj_type ):
136170 # type: (str, Union[T, str]) -> Any
137- """Deserializes payload into ask sdk model object.
171+ """Deserializes payload into a model object.
138172
139173 :param payload: data to be deserialized.
140174 :type payload: str
141175 :param obj_type: resolved class name for deserialized object
142176 :type obj_type: Union[str, object]
143177 :return: deserialized object
144- :rtype: T
178+ :rtype: object
145179 """
146180 if payload is None :
147181 return None
@@ -179,7 +213,7 @@ def __deserialize(self, payload, obj_type):
179213 if obj_type in self .NATIVE_TYPES_MAPPING :
180214 obj_type = self .NATIVE_TYPES_MAPPING [obj_type ]
181215 else :
182- # deserialize ask sdk models
216+ # deserialize models
183217 obj_type = self .__load_class_from_name (obj_type )
184218
185219 if obj_type in self .PRIMITIVE_TYPES :
@@ -194,7 +228,20 @@ def __deserialize(self, payload, obj_type):
194228 return self .__deserialize_model (payload , obj_type )
195229
196230 def __load_class_from_name (self , class_name ):
197- # type: (str) -> str
231+ # type: (str) -> T
232+ """Load the class from the ``class_name`` provided.
233+
234+ Resolve the class name from the ``class_name`` provided, load
235+ the class on path and return the resolved class. If the module
236+ information is not provided in the ``class_name``, then look
237+ for the class on sys ``modules``.
238+
239+ :param class_name: absolute class name to be loaded
240+ :type class_name: str
241+ :return: Resolved class reference
242+ :rtype: object
243+ :raises: :py:class:`ask_sdk_core.exceptions.SerializationException`
244+ """
198245 try :
199246 module_class_list = class_name .rsplit ("." , 1 )
200247 if len (module_class_list ) > 1 :
@@ -223,7 +270,7 @@ def __deserialize_primitive(self, payload, obj_type):
223270 :type obj_type: object
224271 :return: deserialized primitive datatype object
225272 :rtype: object
226- :raises SerializationException
273+ :raises: :py:class:`ask_sdk_core.exceptions. SerializationException`
227274 """
228275 try :
229276 return obj_type (payload )
@@ -247,7 +294,7 @@ def __deserialize_datetime(self, payload, obj_type):
247294 :type obj_type: object
248295 :return: deserialized primitive datatype object
249296 :rtype: object
250- :raises SerializationException
297+ :raises: :py:class:`ask_sdk_core.exceptions. SerializationException`
251298 """
252299 try :
253300 from dateutil .parser import parse
@@ -273,20 +320,25 @@ def __deserialize_model(self, payload, obj_type):
273320 :type obj_type: object
274321 :return: deserialized sdk model object
275322 :rtype: object
276- :raises SerializationException
323+ :raises: :py:class:`ask_sdk_core.exceptions. SerializationException`
277324 """
278325 try :
279326 if issubclass (obj_type , Enum ):
280327 return obj_type (payload )
281328
282- if hasattr (obj_type , 'deserialized_types' ) and hasattr (
283- obj_type , 'attribute_map' ):
329+ if hasattr (obj_type , 'deserialized_types' ):
284330 if hasattr (obj_type , 'get_real_child_model' ):
285331 obj_type = self .__get_obj_by_discriminator (
286332 payload , obj_type )
287333
288334 class_deserialized_types = obj_type .deserialized_types
289- class_attribute_map = obj_type .attribute_map
335+ class_attribute_map = getattr (obj_type , 'attribute_map' , {})
336+ class_attribute_map .update (
337+ {
338+ k : k for k in obj_type .deserialized_types .keys ()
339+ if k not in class_attribute_map
340+ }
341+ )
290342
291343 deserialized_model = obj_type ()
292344 for class_param_name , payload_param_name in iteritems (
@@ -312,7 +364,19 @@ def __deserialize_model(self, payload, obj_type):
312364 raise SerializationException (str (e ))
313365
314366 def __get_obj_by_discriminator (self , payload , obj_type ):
315- # type: (str, Union[T, str]) -> str
367+ # type: (str, Union[T, str]) -> T
368+ """Get correct subclass instance using the discriminator in
369+ payload.
370+
371+ :param payload: Payload for deserialization
372+ :type payload: str
373+ :param obj_type: parent class for deserializing payload into
374+ :type obj_type: object
375+ :return: Subclass of provided parent class, that resolves to
376+ the discriminator in payload.
377+ :rtype: object
378+ :raises: :py:class:`ask_sdk_core.exceptions.SerializationException`
379+ """
316380 namespaced_class_name = obj_type .get_real_child_model (payload )
317381 if not namespaced_class_name :
318382 raise SerializationException (
0 commit comments