From 705c7ad09db65c6ea6fb69bbd417cb7a45f6e3b9 Mon Sep 17 00:00:00 2001 From: Ben Roberts Date: Wed, 5 Dec 2012 17:43:47 -0700 Subject: [PATCH 1/3] added tests and fix for unpickleable metadata in SortedDictWithMetadata --- rest_framework/serializers.py | 12 +++++++- rest_framework/tests/serializer.py | 47 ++++++++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 4519ab053..fcc0744a3 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -22,7 +22,16 @@ class DictWithMetadata(dict): """ 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): @@ -32,6 +41,7 @@ class SortedDictWithMetadata(SortedDict, DictWithMetadata): pass + def _is_protected_type(obj): """ True if the object is a native datatype that does not need to diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 61a05da18..af182917f 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -1,9 +1,9 @@ -import datetime +import datetime, pickle from django.test import TestCase from rest_framework import serializers from rest_framework.tests.models import (ActionItem, Anchor, BasicModel, BlankFieldModel, BlogPost, Book, CallableDefaultValueModel, DefaultValueModel, - ManyToManyModel, Person, ReadOnlyManyToManyModel) + ManyToManyModel, Person, ReadOnlyManyToManyModel, BlogPostComment) class SubComment(object): @@ -641,3 +641,46 @@ class BlankFieldTests(TestCase): """ serializer = self.not_blank_model_serializer_class(data=self.data) 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) From 7f28a784146b9ba6ab303e79597f85a0f8b1e76e Mon Sep 17 00:00:00 2001 From: Ben Roberts Date: Wed, 5 Dec 2012 17:54:21 -0700 Subject: [PATCH 2/3] cleaned up last commit --- rest_framework/tests/serializer.py | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index af182917f..9cedb54b4 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -3,7 +3,7 @@ from django.test import TestCase from rest_framework import serializers from rest_framework.tests.models import (ActionItem, Anchor, BasicModel, BlankFieldModel, BlogPost, Book, CallableDefaultValueModel, DefaultValueModel, - ManyToManyModel, Person, ReadOnlyManyToManyModel, BlogPostComment) + ManyToManyModel, Person, ReadOnlyManyToManyModel) class SubComment(object): @@ -643,27 +643,6 @@ class BlankFieldTests(TestCase): 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 From cb7d9ea5c9843ffa99db4400670a11c3651520cc Mon Sep 17 00:00:00 2001 From: Ben Roberts Date: Thu, 6 Dec 2012 12:45:50 -0700 Subject: [PATCH 3/3] cleaned up white space & docstring styling --- rest_framework/serializers.py | 9 ++++----- rest_framework/tests/serializer.py | 14 ++++++++------ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index fcc0744a3..51e0b6647 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -22,11 +22,11 @@ class DictWithMetadata(dict): """ A dict-like object, that can have additional properties attached. """ - 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. + """ + 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__: @@ -41,7 +41,6 @@ class SortedDictWithMetadata(SortedDict, DictWithMetadata): pass - def _is_protected_type(obj): """ True if the object is a native datatype that does not need to diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 9cedb54b4..31dd36994 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -645,18 +645,20 @@ class BlankFieldTests(TestCase): #test for issue #460 class SerializerPickleTests(TestCase): - """ Test pickleability of the output of Serializers + """ + Test pickleability of the output of Serializers """ def test_pickle_simple_model_serializer_data(self): - """ Test simple serializer + """ + 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__ + """ + 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: