From 9d12610fb6fedc552dd4957ba548251d6c2f34bc Mon Sep 17 00:00:00 2001 From: Milan Cermak Date: Mon, 28 Jan 2019 20:46:45 +0100 Subject: [PATCH 1/2] Makes attribute_map optional for serializing --- ask-sdk-core/ask_sdk_core/serialize.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/ask-sdk-core/ask_sdk_core/serialize.py b/ask-sdk-core/ask_sdk_core/serialize.py index 78050ac..f32c34b 100644 --- a/ask-sdk-core/ask_sdk_core/serialize.py +++ b/ask-sdk-core/ask_sdk_core/serialize.py @@ -101,8 +101,13 @@ def serialize(self, obj): # and attributes which value is not None. # Convert attribute name to json key in # model definition for request. + class_attribute_map = getattr(obj, 'attribute_map', {}) + class_attribute_map.update({k: k for k + in obj.deserialized_types.keys() + if k not in class_attribute_map}) + obj_dict = { - obj.attribute_map[attr]: getattr(obj, attr) + class_attribute_map[attr]: getattr(obj, attr) for attr, _ in iteritems(obj.deserialized_types) if getattr(obj, attr) is not None } @@ -279,14 +284,16 @@ def __deserialize_model(self, payload, obj_type): if issubclass(obj_type, Enum): return obj_type(payload) - if hasattr(obj_type, 'deserialized_types') and hasattr( - obj_type, 'attribute_map'): + if hasattr(obj_type, 'deserialized_types'): if hasattr(obj_type, 'get_real_child_model'): obj_type = self.__get_obj_by_discriminator( payload, obj_type) class_deserialized_types = obj_type.deserialized_types - class_attribute_map = obj_type.attribute_map + class_attribute_map = getattr(obj_type, 'attribute_map', {}) + class_attribute_map.update({k: k for k + in obj_type.deserialized_types.keys() + if k not in class_attribute_map}) deserialized_model = obj_type() for class_param_name, payload_param_name in iteritems( From 7317d62b0c93dd9b04e4ae2195bf5273b44e783e Mon Sep 17 00:00:00 2001 From: Milan Cermak Date: Wed, 30 Jan 2019 00:13:50 +0100 Subject: [PATCH 2/2] Requested PR changes --- ask-sdk-core/ask_sdk_core/serialize.py | 4 +- ask-sdk-core/tests/unit/data/__init__.py | 3 ++ .../tests/unit/data/model_test_object_3.py | 31 +++++++++++++ .../tests/unit/data/model_test_object_4.py | 35 ++++++++++++++ ask-sdk-core/tests/unit/test_serialize.py | 46 +++++++++++++++++++ 5 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 ask-sdk-core/tests/unit/data/model_test_object_3.py create mode 100644 ask-sdk-core/tests/unit/data/model_test_object_4.py diff --git a/ask-sdk-core/ask_sdk_core/serialize.py b/ask-sdk-core/ask_sdk_core/serialize.py index f32c34b..aa803d0 100644 --- a/ask-sdk-core/ask_sdk_core/serialize.py +++ b/ask-sdk-core/ask_sdk_core/serialize.py @@ -67,8 +67,8 @@ def serialize(self, obj): If obj is list, serialize each element in the list. If obj is dict, return the dict with serialized values. If obj is ask sdk model, return the dict with keys resolved - from model's ``attribute_map`` and values serialized - based on ``deserialized_types``. + from the union of model's ``attribute_map`` and ``deserialized_types`` + and values serialized based on ``deserialized_types``. :param obj: The data to serialize. :type obj: object diff --git a/ask-sdk-core/tests/unit/data/__init__.py b/ask-sdk-core/tests/unit/data/__init__.py index 99271b2..cd291b7 100644 --- a/ask-sdk-core/tests/unit/data/__init__.py +++ b/ask-sdk-core/tests/unit/data/__init__.py @@ -15,9 +15,12 @@ # specific language governing permissions and limitations under the # License. # + from .model_enum_object import ModelEnumObject from .model_test_object_1 import ModelTestObject1 from .model_test_object_2 import ModelTestObject2 +from .model_test_object_3 import ModelTestObject3 +from .model_test_object_4 import ModelTestObject4 from .invalid_model_object import InvalidModelObject from .model_abstract_parent_object import ModelAbstractParentObject from .model_child_objects import ModelChildObject1 diff --git a/ask-sdk-core/tests/unit/data/model_test_object_3.py b/ask-sdk-core/tests/unit/data/model_test_object_3.py new file mode 100644 index 0000000..51fbb5b --- /dev/null +++ b/ask-sdk-core/tests/unit/data/model_test_object_3.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights +# Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). +# You may not use this file except in compliance with the License. +# A copy of the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is +# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS +# OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the +# License. +# + + +class ModelTestObject3(object): + deserialized_types = { + 'str_var': 'str', + 'int_var': 'int' + } + + def __init__(self, str_var=None, int_var=None): + self.str_var = str_var + self.int_var = int_var + + def __eq__(self, other): + return self.__dict__ == other.__dict__ diff --git a/ask-sdk-core/tests/unit/data/model_test_object_4.py b/ask-sdk-core/tests/unit/data/model_test_object_4.py new file mode 100644 index 0000000..faf2f17 --- /dev/null +++ b/ask-sdk-core/tests/unit/data/model_test_object_4.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights +# Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). +# You may not use this file except in compliance with the License. +# A copy of the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is +# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS +# OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the +# License. +# + + +class ModelTestObject4(object): + deserialized_types = { + 'str_var': 'str', + 'float_var': 'float' + } + + attribute_map = { + 'float_var': 'floatingValue' + } + + def __init__(self, str_var=None, float_var=None): + self.str_var = str_var + self.float_var = float_var + + def __eq__(self, other): + return self.__dict__ == other.__dict__ diff --git a/ask-sdk-core/tests/unit/test_serialize.py b/ask-sdk-core/tests/unit/test_serialize.py index 15fdb41..eb31ca6 100644 --- a/ask-sdk-core/tests/unit/test_serialize.py +++ b/ask-sdk-core/tests/unit/test_serialize.py @@ -132,6 +132,24 @@ def test_model_obj_serialization(self): assert self.test_serializer.serialize(test_model_obj_1) == expected_serialized_obj, \ "Default Serializer serialized model object incorrectly" + def test_model_obj_without_attrmap_serialization(self): + test_obj_inst = data.ModelTestObject3(str_var="test", int_var=123) + expected_dict = { + "str_var": "test", + "int_var": 123 + } + assert self.test_serializer.serialize(test_obj_inst) == expected_dict, \ + "Default Serializer serialized object without attribute_map incorrectly" + + def test_model_obj_with_incomplete_attrmap_serialization(self): + test_obj_inst = data.ModelTestObject4(str_var="test", float_var=3.14) + expected_dict = { + "str_var": "test", + "floatingValue": 3.14 + } + assert self.test_serializer.serialize(test_obj_inst) == expected_dict, \ + "Default Serializer serialized object with incomplete attribute map incorrectly" + def test_enum_obj_serialization(self): test_model_obj_2 = data.ModelTestObject2(int_var=123) test_enum_obj = data.ModelEnumObject("ENUM_VAL_1") @@ -406,6 +424,34 @@ def test_model_obj_with_additional_params_in_payload_deserialization(self): test_payload, test_obj_type) == expected_obj, ( "Default Serializer deserialized model object incorrectly when payload has additional parameters") + def test_model_obj_without_attrmap_deserialization(self): + test_payload = { + "str_var": "Test", + "int_var": 123 + } + test_obj_type = data.ModelTestObject3 + expected_obj = data.ModelTestObject3(str_var="Test", int_var=123) + + with patch("json.loads") as mock_json_loader: + mock_json_loader.return_value = test_payload + assert self.test_serializer.deserialize( + test_payload, test_obj_type) == expected_obj, ( + "Default Serializer deserialized model object without attribute map incorrectly") + + def test_model_obj_with_incomplete_attrmap_deserialization(self): + test_payload = { + "str_var": "Test", + "floatingValue": 3.14 + } + test_obj_type = data.ModelTestObject4 + expected_obj = data.ModelTestObject4(str_var="Test", float_var=3.14) + + with patch("json.loads") as mock_json_loader: + mock_json_loader.return_value = test_payload + assert self.test_serializer.deserialize( + test_payload, test_obj_type) == expected_obj, ( + "Default Serializer deserialized model object with incomplete attribute map incorrectly") + def test_invalid_model_obj_deserialization(self): test_payload = { "var_1": "some value"