@@ -113,31 +113,38 @@ def _get_subtype_map(cls):
113113 return base ._subtype_map
114114 return {}
115115
116+ @classmethod
117+ def _flatten_subtype (cls , key , objects ):
118+ if not '_subtype_map' in cls .__dict__ :
119+ return {}
120+ result = dict (cls ._subtype_map [key ])
121+ for valuetype in cls ._subtype_map [key ].values ():
122+ result .update (objects [valuetype ]._flatten_subtype (key , objects ))
123+ return result
124+
116125 @classmethod
117126 def _classify (cls , response , objects ):
118127 """Check the class _subtype_map for any child classes.
119- We want to ignore any inheirited _subtype_maps.
128+ We want to ignore any inherited _subtype_maps.
129+ Remove the polymorphic key from the initial data.
120130 """
121- try :
122- map = cls . __dict__ . get ( '_subtype_map' , {})
131+ for subtype_key in cls . __dict__ . get ( '_subtype_map' , {}). keys () :
132+ subtype_value = None
123133
124- for _type , _classes in map . items ():
125- classification = response .get ( _type )
126- try :
127- return objects [ _classes [ classification ]]
128- except KeyError :
129- pass
134+ rest_api_response_key = _decode_attribute_map_key ( cls . _attribute_map [ subtype_key ][ 'key' ])
135+ subtype_value = response . pop ( rest_api_response_key , None ) or response .pop ( subtype_key , None )
136+ if subtype_value :
137+ flatten_mapping_type = cls . _flatten_subtype ( subtype_key , objects )
138+ return objects [ flatten_mapping_type [ subtype_value ]]
139+ return cls
130140
131- for c in _classes :
132- try :
133- _cls = objects [_classes [c ]]
134- return _cls ._classify (response , objects )
135- except (KeyError , TypeError ):
136- continue
137- raise TypeError ("Object cannot be classified futher." )
138- except AttributeError :
139- raise TypeError ("Object cannot be classified futher." )
141+ def _decode_attribute_map_key (key ):
142+ """This decode a key in an _attribute_map to the actual key we want to look at
143+ inside the received data.
140144
145+ :param str key: A key string from the generated code
146+ """
147+ return key .replace ('\\ .' , '.' )
141148
142149def _convert_to_datatype (data , data_type , localtypes ):
143150 if data is None :
@@ -157,6 +164,7 @@ def _convert_to_datatype(data, data_type, localtypes):
157164 elif issubclass (data_obj , Enum ):
158165 return data
159166 elif not isinstance (data , data_obj ):
167+ data_obj = data_obj ._classify (data , localtypes )
160168 result = {
161169 key : _convert_to_datatype (
162170 data [key ],
@@ -195,7 +203,7 @@ class Serializer(object):
195203 "unique" : lambda x , y : len (x ) != len (set (x )),
196204 "multiple" : lambda x , y : x % y != 0
197205 }
198- flattten = re .compile (r"(?<!\\)\." )
206+ flatten = re .compile (r"(?<!\\)\." )
199207
200208 def __init__ (self , classes = None ):
201209 self .serialize_type = {
@@ -241,14 +249,12 @@ def _serialize(self, target_obj, data_type=None, **kwargs):
241249
242250 try :
243251 attributes = target_obj ._attribute_map
244- self ._classify_data (target_obj , class_name , serialized )
245-
246252 for attr , map in attributes .items ():
247253 attr_name = attr
248254 debug_name = "{}.{}" .format (class_name , attr_name )
249255 try :
250- keys = self .flattten .split (map ['key' ])
251- keys = [k . replace ( ' \\ .' , '.' ) for k in keys ]
256+ keys = self .flatten .split (map ['key' ])
257+ keys = [_decode_attribute_map_key ( k ) for k in keys ]
252258 attr_type = map ['type' ]
253259 orig_attr = getattr (target_obj , attr )
254260 validation = target_obj ._validation .get (attr_name , {})
@@ -278,18 +284,6 @@ def _serialize(self, target_obj, data_type=None, **kwargs):
278284 else :
279285 return serialized
280286
281- def _classify_data (self , target_obj , class_name , serialized ):
282- """Check whether this object is a child and therefor needs to be
283- classified in the message.
284- """
285- try :
286- for _type , _classes in target_obj ._get_subtype_map ().items ():
287- for ref , name in _classes .items ():
288- if name == class_name :
289- serialized [_type ] = ref
290- except AttributeError :
291- pass # TargetObj has no _subtype_map so we don't need to classify.
292-
293287 def body (self , data , data_type , ** kwargs ):
294288 """Serialize data intended for a request body.
295289
@@ -752,9 +746,9 @@ def __call__(self, target_obj, response_data):
752746 while '.' in key :
753747 dict_keys = self .flatten .split (key )
754748 if len (dict_keys ) == 1 :
755- key = dict_keys [0 ]. replace ( ' \\ .' , '.' )
749+ key = _decode_attribute_map_key ( dict_keys [0 ])
756750 break
757- working_key = dict_keys [0 ]. replace ( ' \\ .' , '.' )
751+ working_key = _decode_attribute_map_key ( dict_keys [0 ])
758752 working_data = working_data .get (working_key , data )
759753 key = '.' .join (dict_keys [1 :])
760754
@@ -786,8 +780,8 @@ def _classify_target(self, target, data):
786780
787781 try :
788782 target = target ._classify (data , self .dependencies )
789- except ( TypeError , AttributeError ) :
790- pass # Target has no subclasses, so can't classify further.
783+ except AttributeError :
784+ pass # Target is not a Model, no classify
791785 return target , target .__class__ .__name__
792786
793787 def _unpack_content (self , raw_data ):
0 commit comments