Fix and test for #645

Yuck, pickle is weird.  Closes #645.
This commit is contained in:
Tom Christie 2013-02-22 22:59:55 +00:00
parent d62e4a7aa5
commit e1f0001f92
2 changed files with 22 additions and 13 deletions

View File

@ -28,20 +28,23 @@ class DictWithMetadata(dict):
def __getstate__(self): def __getstate__(self):
""" """
Used by pickle (e.g., caching). Used by pickle (e.g., caching).
Overriden to remove metadata from the dict, since it shouldn't be pickled Overriden to remove the metadata from the dict, since it shouldn't be
and may in some instances be unpickleable. pickled and may in some instances be unpickleable.
""" """
# return an instance of the first dict in MRO that isn't a DictWithMetadata return dict(self)
for base in self.__class__.__mro__:
if not issubclass(base, DictWithMetadata) and issubclass(base, dict):
return base(self)
class SortedDictWithMetadata(SortedDict, DictWithMetadata): class SortedDictWithMetadata(SortedDict):
""" """
A sorted dict-like object, that can have additional properties attached. A sorted dict-like object, that can have additional properties attached.
""" """
pass def __getstate__(self):
"""
Used by pickle (e.g., caching).
Overriden to remove the metadata from the dict, since it shouldn't be
pickle and may in some instances be unpickleable.
"""
return SortedDict(self).__dict__
def _is_protected_type(obj): def _is_protected_type(obj):

View File

@ -951,15 +951,21 @@ class SerializerPickleTests(TestCase):
class Meta: class Meta:
model = Person model = Person
fields = ('name', 'age') fields = ('name', 'age')
pickle.dumps(InnerPersonSerializer(Person(name="Noah", age=950)).data) pickle.dumps(InnerPersonSerializer(Person(name="Noah", age=950)).data, 0)
def test_getstate_method_should_not_return_none(self): def test_getstate_method_should_not_return_none(self):
""" """
Regression test for Regression test for #645.
https://github.com/tomchristie/django-rest-framework/issues/645
""" """
d = serializers.DictWithMetadata({1: 1}) data = serializers.DictWithMetadata({1: 1})
self.assertEqual(d.__getstate__(), serializers.SortedDict({1: 1})) self.assertEqual(data.__getstate__(), serializers.SortedDict({1: 1}))
def test_serializer_data_is_pickleable(self):
"""
Another regression test for #645.
"""
data = serializers.SortedDictWithMetadata({1: 1})
repr(pickle.loads(pickle.dumps(data, 0)))
class DepthTest(TestCase): class DepthTest(TestCase):