added tests and fix for unpickleable metadata in SortedDictWithMetadata

This commit is contained in:
Ben Roberts 2012-12-05 17:43:47 -07:00
parent 3868241f6a
commit 705c7ad09d
2 changed files with 56 additions and 3 deletions

View File

@ -22,7 +22,16 @@ class DictWithMetadata(dict):
""" """
A dict-like object, that can have additional properties attached. A dict-like object, that can have additional properties attached.
""" """
pass
def __getstate__(self):
""" Used by pickle (e.g., caching).
Overriden to remove metadata from the dict, since it shouldn't be pickled
and may in some instances be unpickleable.
"""
# return an instance of the first dict in MRO that isn't a DictWithMetadata
for base in self.__class__.__mro__:
if not isinstance(base, DictWithMetadata) and isinstance(base, dict):
return base(self)
class SortedDictWithMetadata(SortedDict, DictWithMetadata): class SortedDictWithMetadata(SortedDict, DictWithMetadata):
@ -32,6 +41,7 @@ class SortedDictWithMetadata(SortedDict, DictWithMetadata):
pass pass
def _is_protected_type(obj): def _is_protected_type(obj):
""" """
True if the object is a native datatype that does not need to True if the object is a native datatype that does not need to

View File

@ -1,9 +1,9 @@
import datetime import datetime, pickle
from django.test import TestCase from django.test import TestCase
from rest_framework import serializers from rest_framework import serializers
from rest_framework.tests.models import (ActionItem, Anchor, BasicModel, from rest_framework.tests.models import (ActionItem, Anchor, BasicModel,
BlankFieldModel, BlogPost, Book, CallableDefaultValueModel, DefaultValueModel, BlankFieldModel, BlogPost, Book, CallableDefaultValueModel, DefaultValueModel,
ManyToManyModel, Person, ReadOnlyManyToManyModel) ManyToManyModel, Person, ReadOnlyManyToManyModel, BlogPostComment)
class SubComment(object): class SubComment(object):
@ -641,3 +641,46 @@ class BlankFieldTests(TestCase):
""" """
serializer = self.not_blank_model_serializer_class(data=self.data) serializer = self.not_blank_model_serializer_class(data=self.data)
self.assertEquals(serializer.is_valid(), False) self.assertEquals(serializer.is_valid(), False)
#class PersonGroup(object):
# name = "group"
# persons = [Person(name="joe"), Person(name="job")]
#
#class PersonGroupSerializer(serializers.Serializer):
# name = serializers.CharField()
# persons = PersonSerializer()
#
#class BlogPostSerializer(serializers.ModelSerializer):
# class Meta:
# model = BlogPost
#
#
#class BlogPostCommentSerializer(serializers.ModelSerializer):
# class Meta:
# model = BlogPostComment
# fields = ('text', 'blog_post')
#
# blog_post = BlogPostSerializer()
#
#test for issue #460
class SerializerPickleTests(TestCase):
""" Test pickleability of the output of Serializers
"""
def test_pickle_simple_model_serializer_data(self):
""" Test simple serializer
"""
pickle.dumps(PersonSerializer(Person(name="Methusela", age=969)).data)
def test_pickle_inner_serializer(self):
""" Test pickling a serializer whose resulting .data (a SortedDictWithMetadata) will
have unpickleable meta data--in order to make sure metadata doesn't get pulled into the pickle.
See DictWithMetadata.__getstate__
"""
class InnerPersonSerializer(serializers.ModelSerializer):
class Meta:
model = Person
fields = ('name', 'age')
pickle.dumps(InnerPersonSerializer(Person(name="Noah", age=950)).data)