From be66e15c1c14855970c9b33b9c027e67ea31d9ea Mon Sep 17 00:00:00 2001 From: kazmiruk Date: Thu, 23 Apr 2015 16:29:39 +0700 Subject: [PATCH] renaming of OrderedDict back to SortedDict + some comments --- rest_framework/compat.py | 13 +++++++++++-- rest_framework/fields.py | 6 +++--- rest_framework/routers.py | 6 +++--- rest_framework/serializers.py | 31 ++++++++++++++++++------------- rest_framework/utils/encoders.py | 12 ++++++------ rest_framework/views.py | 4 ++-- tests/test_serializer.py | 4 ++-- 7 files changed, 45 insertions(+), 31 deletions(-) diff --git a/rest_framework/compat.py b/rest_framework/compat.py index 29036b1de..8532a0172 100644 --- a/rest_framework/compat.py +++ b/rest_framework/compat.py @@ -266,11 +266,20 @@ except ImportError: klass.__str__ = lambda self: self.__unicode__().encode('utf-8') return klass +""" +SortedDict deprecated since django 1.8. There is collections.OrderedDict +which available since python 2.7 and python 3.1. There are no need of other +checks because of django 1.7+ requires python 2.7+ +""" try: - from collections import OrderedDict + from collections import OrderedDict as SortedDict except ImportError: - from django.utils.datastructures import SortedDict as OrderedDict + from django.utils.datastructures import SortedDict +""" +GenericForeignKey moves from generic to fields in django 1.9 and in 1.8 shows +deprecation warnings +""" if django.VERSION >= (1, 8): from django.contrib.contenttypes.fields import GenericForeignKey else: diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 9e95e6dc2..d310c5df3 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -25,7 +25,7 @@ from django.utils.translation import ugettext_lazy as _ from django.utils.dateparse import parse_date, parse_datetime, parse_time from rest_framework import ISO_8601 from rest_framework.compat import ( - BytesIO, smart_text, OrderedDict, + BytesIO, smart_text, SortedDict, force_text, is_non_str_iterable ) from rest_framework.settings import api_settings @@ -224,7 +224,7 @@ class Field(object): return [self.to_native(item) for item in value] elif isinstance(value, dict): # Make sure we preserve field ordering, if it exists - ret = OrderedDict() + ret = SortedDict() for key, val in value.items(): ret[key] = self.to_native(val) return ret @@ -239,7 +239,7 @@ class Field(object): return {} def metadata(self): - metadata = OrderedDict() + metadata = SortedDict() metadata['type'] = self.type_label metadata['required'] = getattr(self, 'required', False) optional_attrs = ['read_only', 'label', 'help_text', diff --git a/rest_framework/routers.py b/rest_framework/routers.py index 6e99f14de..9e5813b39 100644 --- a/rest_framework/routers.py +++ b/rest_framework/routers.py @@ -21,7 +21,7 @@ from django.conf.urls import patterns, url from django.core.exceptions import ImproperlyConfigured from django.core.urlresolvers import NoReverseMatch from rest_framework import views -from rest_framework.compat import OrderedDict +from rest_framework.compat import SortedDict from rest_framework.response import Response from rest_framework.reverse import reverse from rest_framework.urlpatterns import format_suffix_patterns @@ -278,7 +278,7 @@ class DefaultRouter(SimpleRouter): """ Return a view to use as the API root. """ - api_root_dict = OrderedDict() + api_root_dict = SortedDict() list_name = self.routes[0].name for prefix, viewset, basename in self.registry: api_root_dict[prefix] = list_name.format(basename=basename) @@ -287,7 +287,7 @@ class DefaultRouter(SimpleRouter): _ignore_model_permissions = True def get(self, request, *args, **kwargs): - ret = OrderedDict() + ret = SortedDict() for key, url_name in api_root_dict.items(): try: ret[key] = reverse( diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 14d614e65..79984526d 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -22,7 +22,7 @@ from django.forms import widgets from django.utils import six from django.utils.functional import cached_property from django.core.exceptions import ObjectDoesNotExist -from rest_framework.compat import OrderedDict, GenericForeignKey +from rest_framework.compat import SortedDict, GenericForeignKey from rest_framework.settings import api_settings @@ -105,20 +105,25 @@ class DictWithMetadata(dict): return dict(self) -class OrderedDictWithMetadata(OrderedDict): +class SortedDictWithMetadata(SortedDict): """ A sorted dict-like object, that can have additional properties attached. """ def __reduce__(self): - return self.__class__, (OrderedDict(self), ) - - def __getstate__(self): """ - Used by pickle (e.g., caching). + Used by pickle (e.g., caching) if OrderedDict is used instead of SortedDict Overriden to remove the metadata from the dict, since it shouldn't be pickle and may in some instances be unpickleable. """ - return OrderedDict(self).__dict__ + return self.__class__, (SortedDict(self), ) + + def __getstate__(self): + """ + Used by pickle (e.g., caching) in SortedDict + 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): @@ -154,7 +159,7 @@ def _get_declared_fields(bases, attrs): if hasattr(base, 'base_fields'): fields = list(base.base_fields.items()) + fields - return OrderedDict(fields) + return SortedDict(fields) class SerializerMetaclass(type): @@ -182,7 +187,7 @@ class BaseSerializer(WritableField): pass _options_class = SerializerOptions - _dict_class = OrderedDictWithMetadata + _dict_class = SortedDictWithMetadata def __init__(self, instance=None, data=None, files=None, context=None, partial=False, many=False, @@ -231,7 +236,7 @@ class BaseSerializer(WritableField): This will be the set of any explicitly declared fields, plus the set of fields returned by get_default_fields(). """ - ret = OrderedDict() + ret = SortedDict() # Get the explicitly declared fields base_fields = copy.deepcopy(self.base_fields) @@ -247,7 +252,7 @@ class BaseSerializer(WritableField): # If 'fields' is specified, use those fields, in that order. if self.opts.fields: assert isinstance(self.opts.fields, (list, tuple)), '`fields` must be a list or tuple' - new = OrderedDict() + new = SortedDict() for key in self.opts.fields: new[key] = ret[key] ret = new @@ -608,7 +613,7 @@ class BaseSerializer(WritableField): Useful for things like responding to OPTIONS requests, or generating API schemas for auto-documentation. """ - return OrderedDict( + return SortedDict( [ (field_name, field.metadata()) for field_name, field in six.iteritems(self.fields) @@ -685,7 +690,7 @@ class ModelSerializer(Serializer): self.__class__.__name__ ) opts = cls._meta.concrete_model._meta - ret = OrderedDict() + ret = SortedDict() nested = bool(self.opts.depth) # Deal with adding the primary key field diff --git a/rest_framework/utils/encoders.py b/rest_framework/utils/encoders.py index c2bb60c67..813108b77 100644 --- a/rest_framework/utils/encoders.py +++ b/rest_framework/utils/encoders.py @@ -5,8 +5,8 @@ from __future__ import unicode_literals from django.utils import timezone from django.db.models.query import QuerySet from django.utils.functional import Promise -from rest_framework.compat import force_text, OrderedDict -from rest_framework.serializers import DictWithMetadata, OrderedDictWithMetadata +from rest_framework.compat import force_text, SortedDict +from rest_framework.serializers import DictWithMetadata, SortedDictWithMetadata import datetime import decimal import types @@ -66,7 +66,7 @@ else: class SafeDumper(yaml.SafeDumper): """ Handles decimals as strings. - Handles OrderedDicts as usual dicts, but preserves field order, rather + Handles SortedDicts as usual dicts, but preserves field order, rather than the usual behaviour of sorting the keys. """ def represent_decimal(self, data): @@ -80,7 +80,7 @@ else: best_style = True if hasattr(mapping, 'items'): mapping = list(mapping.items()) - if not isinstance(mapping, OrderedDict): + if not isinstance(mapping, SortedDict): mapping.sort() for item_key, item_value in mapping: node_key = self.represent_data(item_key) @@ -102,7 +102,7 @@ else: SafeDumper.represent_decimal ) SafeDumper.add_representer( - OrderedDict, + SortedDict, yaml.representer.SafeRepresenter.represent_dict ) SafeDumper.add_representer( @@ -110,7 +110,7 @@ else: yaml.representer.SafeRepresenter.represent_dict ) SafeDumper.add_representer( - OrderedDictWithMetadata, + SortedDictWithMetadata, yaml.representer.SafeRepresenter.represent_dict ) SafeDumper.add_representer( diff --git a/rest_framework/views.py b/rest_framework/views.py index 526931e60..fb30775b1 100644 --- a/rest_framework/views.py +++ b/rest_framework/views.py @@ -7,7 +7,7 @@ from django.core.exceptions import PermissionDenied from django.http import Http404 from django.views.decorators.csrf import csrf_exempt from rest_framework import status, exceptions -from rest_framework.compat import smart_text, HttpResponseBase, OrderedDict, View +from rest_framework.compat import smart_text, HttpResponseBase, SortedDict, View from rest_framework.request import Request from rest_framework.response import Response from rest_framework.settings import api_settings @@ -420,7 +420,7 @@ class APIView(View): # By default we can't provide any form-like information, however the # generic views override this implementation and add additional # information for POST and PUT methods, based on the serializer. - ret = OrderedDict() + ret = SortedDict() ret['name'] = self.get_view_name() ret['description'] = self.get_view_description() ret['renders'] = [renderer.media_type for renderer in self.renderer_classes] diff --git a/tests/test_serializer.py b/tests/test_serializer.py index c0de5cf27..14e88e6d2 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -1297,7 +1297,7 @@ class SerializerPickleTests(TestCase): def test_pickle_inner_serializer(self): """ - Test pickling a serializer whose resulting .data (a OrderedDictWithMetadata) will + 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__ """ @@ -1318,7 +1318,7 @@ class SerializerPickleTests(TestCase): """ Another regression test for #645. """ - data = serializers.OrderedDictWithMetadata({1: 1}) + data = serializers.SortedDictWithMetadata({1: 1}) repr(pickle.loads(pickle.dumps(data, 0)))