10
10
from dateutil .parser import parse
11
11
from dateutil .tz import tzutc
12
12
13
- from mock import patch
13
+ from mock import patch , Mock , call
14
14
15
15
from pynamodb .compat import CompatTestCase as TestCase
16
16
from pynamodb .constants import UTC , DATETIME_FORMAT
19
19
from pynamodb .attributes import (
20
20
BinarySetAttribute , BinaryAttribute , NumberSetAttribute , NumberAttribute ,
21
21
UnicodeAttribute , UnicodeSetAttribute , UTCDateTimeAttribute , BooleanAttribute , LegacyBooleanAttribute ,
22
- MapAttribute , ListAttribute ,
22
+ MapAttribute , ListAttribute , Attribute ,
23
23
JSONAttribute , DEFAULT_ENCODING , NUMBER , STRING , STRING_SET , NUMBER_SET , BINARY_SET ,
24
24
BINARY , MAP , LIST , BOOLEAN , _get_value_for_deserialize )
25
25
@@ -395,7 +395,7 @@ def test_unicode_set_deserialize(self):
395
395
value
396
396
)
397
397
398
- def test_unicode_set_deserialize (self ):
398
+ def test_unicode_set_deserialize_old_way (self ):
399
399
"""
400
400
UnicodeSetAttribute.deserialize old way
401
401
"""
@@ -655,6 +655,34 @@ class SomeModel(Model):
655
655
self .assertEqual (json .dumps ({'map_attr' : {'foo' : 'bar' }}),
656
656
json .dumps (item .typed_map .as_dict ()))
657
657
658
+ def test_json_serialize (self ):
659
+ class JSONMapAttribute (MapAttribute ):
660
+ arbitrary_data = JSONAttribute ()
661
+
662
+ def __eq__ (self , other ):
663
+ return self .arbitrary_data == other .arbitrary_data
664
+
665
+ item = {'foo' : 'bar' , 'bool' : True , 'number' : 3.141 }
666
+ json_map = JSONMapAttribute (arbitrary_data = item )
667
+ serialized = json_map .serialize (json_map )
668
+ deserialized = json_map .deserialize (serialized )
669
+ self .assertTrue (isinstance (deserialized , JSONMapAttribute ))
670
+ self .assertEqual (deserialized , json_map )
671
+ self .assertEqual (deserialized .arbitrary_data , item )
672
+
673
+ def test_serialize_datetime (self ):
674
+ class CustomMapAttribute (MapAttribute ):
675
+ date_attr = UTCDateTimeAttribute ()
676
+
677
+ cm = CustomMapAttribute (date_attr = datetime (2017 , 1 , 1 ))
678
+ serialized_datetime = cm .serialize (cm )
679
+ expected_serialized_value = {
680
+ 'date_attr' : {
681
+ 'S' : u'2017-01-01T00:00:00.000000+0000'
682
+ }
683
+ }
684
+ self .assertEquals (serialized_datetime , expected_serialized_value )
685
+
658
686
659
687
class ValueDeserializeTestCase (TestCase ):
660
688
def test__get_value_for_deserialize (self ):
@@ -728,8 +756,8 @@ def __lt__(self, other):
728
756
return self .name < other .name
729
757
730
758
def __eq__ (self , other ):
731
- return self .name == other .name and \
732
- self .age == other .age
759
+ return ( self .name == other .name and
760
+ self .age == other .age )
733
761
734
762
person1 = Person ()
735
763
person1 .name = 'john'
@@ -738,13 +766,65 @@ def __eq__(self, other):
738
766
person2 = Person ()
739
767
person2 .name = 'Dana'
740
768
person2 .age = 41
769
+
741
770
inp = [person1 , person2 ]
742
771
743
772
list_attribute = ListAttribute (default = [], of = Person )
744
773
serialized = list_attribute .serialize (inp )
745
774
deserialized = list_attribute .deserialize (serialized )
746
775
self .assertEqual (sorted (deserialized ), sorted (inp ))
747
776
777
+ def test_list_of_map_with_of_and_custom_attribute (self ):
778
+
779
+ # Create a couple of mock functions to use
780
+ # to test that the CustomAttribute serialize/deserialize are called
781
+ serialize_mock = Mock ()
782
+ deserialize_mock = Mock ()
783
+
784
+ class CustomAttribute (Attribute ):
785
+ attr_type = STRING
786
+
787
+ def serialize (self , value ):
788
+ serialize_mock (value )
789
+ return value .upper ()
790
+
791
+ def deserialize (self , value ):
792
+ deserialize_mock (value )
793
+ return value .lower ()
794
+
795
+ class CustomMapAttribute (MapAttribute ):
796
+ custom = CustomAttribute ()
797
+
798
+ def __lt__ (self , other ):
799
+ return self .custom < other .custom
800
+
801
+ def __eq__ (self , other ):
802
+ return self .custom == other .custom
803
+
804
+ attribute1 = CustomMapAttribute ()
805
+ attribute1 .custom = 'test-value1'
806
+
807
+ attribute2 = CustomMapAttribute ()
808
+ attribute2 .custom = 'test-value2'
809
+
810
+ inp = [attribute1 , attribute2 ]
811
+
812
+ list_attribute = ListAttribute (default = [], of = CustomMapAttribute )
813
+ serialized = list_attribute .serialize (inp )
814
+ deserialized = list_attribute .deserialize (serialized )
815
+ self .assertEqual (sorted (deserialized ), sorted (inp ))
816
+
817
+ # Confirm that the the serialize/deserialize are called
818
+ # with the expected values
819
+ serialize_mock .assert_has_calls ([
820
+ call ('test-value1' ),
821
+ call ('test-value2' ),
822
+ ])
823
+ deserialize_mock .assert_has_calls ([
824
+ call ('TEST-VALUE1' ),
825
+ call ('TEST-VALUE2' ),
826
+ ])
827
+
748
828
def test_list_of_unicode_with_of (self ):
749
829
with self .assertRaises (ValueError ):
750
830
ListAttribute (default = [], of = UnicodeAttribute )
0 commit comments