Removed django.utils.datastructures.SortedDict per deprecation timeline.

This commit is contained in:
Tim Graham 2014-11-19 12:22:23 -05:00
parent 41f0d3d3bc
commit c820892eed
6 changed files with 6 additions and 287 deletions

View File

@ -1,132 +1,7 @@
import copy
import warnings
from collections import OrderedDict
from django.utils import six
from django.utils.deprecation import RemovedInDjango19Warning
class SortedDict(dict):
"""
A dictionary that keeps its keys in the order in which they're inserted.
"""
def __new__(cls, *args, **kwargs):
instance = super(SortedDict, cls).__new__(cls, *args, **kwargs)
instance.keyOrder = []
return instance
def __init__(self, data=None):
warnings.warn(
"SortedDict is deprecated and will be removed in Django 1.9.",
RemovedInDjango19Warning, stacklevel=2
)
if data is None or isinstance(data, dict):
data = data or []
super(SortedDict, self).__init__(data)
self.keyOrder = list(data) if data else []
else:
super(SortedDict, self).__init__()
super_set = super(SortedDict, self).__setitem__
for key, value in data:
# Take the ordering from first key
if key not in self:
self.keyOrder.append(key)
# But override with last value in data (dict() does this)
super_set(key, value)
def __deepcopy__(self, memo):
return self.__class__([(key, copy.deepcopy(value, memo))
for key, value in self.items()])
def __copy__(self):
# The Python's default copy implementation will alter the state
# of self. The reason for this seems complex but is likely related to
# subclassing dict.
return self.copy()
def __setitem__(self, key, value):
if key not in self:
self.keyOrder.append(key)
super(SortedDict, self).__setitem__(key, value)
def __delitem__(self, key):
super(SortedDict, self).__delitem__(key)
self.keyOrder.remove(key)
def __iter__(self):
return iter(self.keyOrder)
def __reversed__(self):
return reversed(self.keyOrder)
def pop(self, k, *args):
result = super(SortedDict, self).pop(k, *args)
try:
self.keyOrder.remove(k)
except ValueError:
# Key wasn't in the dictionary in the first place. No problem.
pass
return result
def popitem(self):
result = super(SortedDict, self).popitem()
self.keyOrder.remove(result[0])
return result
def _iteritems(self):
for key in self.keyOrder:
yield key, self[key]
def _iterkeys(self):
for key in self.keyOrder:
yield key
def _itervalues(self):
for key in self.keyOrder:
yield self[key]
if six.PY3:
items = _iteritems
keys = _iterkeys
values = _itervalues
else:
iteritems = _iteritems
iterkeys = _iterkeys
itervalues = _itervalues
def items(self):
return [(k, self[k]) for k in self.keyOrder]
def keys(self):
return self.keyOrder[:]
def values(self):
return [self[k] for k in self.keyOrder]
def update(self, dict_):
for k, v in six.iteritems(dict_):
self[k] = v
def setdefault(self, key, default):
if key not in self:
self.keyOrder.append(key)
return super(SortedDict, self).setdefault(key, default)
def copy(self):
"""Returns a copy of this object."""
# This way of initializing the copy means it works for subclasses, too.
return self.__class__(self)
def __repr__(self):
"""
Replaces the normal dict.__repr__ with a version that returns the keys
in their sorted order.
"""
return '{%s}' % ', '.join('%r: %r' % (k, v) for k, v in six.iteritems(self))
def clear(self):
super(SortedDict, self).clear()
self.keyOrder = []
class OrderedSet(object):

View File

@ -97,34 +97,6 @@ need to distinguish caches by the ``Accept-language`` header.
cache, this just means that we have to build the response once to get at
the Vary header and so at the list of headers to use for the cache key.
``django.utils.datastructures``
===============================
.. module:: django.utils.datastructures
:synopsis: Data structures that aren't in Python's standard library.
.. class:: SortedDict
.. deprecated:: 1.7
``SortedDict`` is deprecated and will be removed in Django 1.9. Use
:class:`collections.OrderedDict` instead.
The :class:`django.utils.datastructures.SortedDict` class is a dictionary
that keeps its keys in the order in which they're inserted.
Creating a new SortedDict
-------------------------
Creating a new ``SortedDict`` must be done in a way where ordering is
guaranteed. For example::
SortedDict({'b': 1, 'a': 2, 'c': 3})
will not work. Passing in a basic Python ``dict`` could produce unreliable
results. Instead do::
SortedDict([('b', 1), ('a', 2), ('c', 3)])
``django.utils.dateparse``
==========================

View File

@ -714,12 +714,12 @@ Data structures
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``django.newforms.forms.SortedDictFromList`` was removed.
:class:`django.utils.datastructures.SortedDict` can now be instantiated with
``django.utils.datastructures.SortedDict`` can now be instantiated with
a sequence of tuples.
To update your code:
1. Use :class:`django.utils.datastructures.SortedDict` wherever you were
1. Use ``django.utils.datastructures.SortedDict`` wherever you were
using ``django.newforms.forms.SortedDictFromList``.
2. Because ``django.utils.datastructures.SortedDict.copy`` doesn't

View File

@ -1511,8 +1511,7 @@ Python versions, this module isn't useful anymore. It has been deprecated. Use
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As :class:`~collections.OrderedDict` was added to the standard library in
Python 2.7, :class:`~django.utils.datastructures.SortedDict` is no longer
needed and has been deprecated.
Python 2.7, ``SortedDict`` is no longer needed and has been deprecated.
Custom SQL location for models package
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -181,7 +181,7 @@ versions of Python.
:meth:`dict.keys`, :meth:`dict.items` and :meth:`dict.values` return lists in
Python 2 and iterators in Python 3. :class:`~django.http.QueryDict` and the
:class:`dict`-like classes defined in :mod:`django.utils.datastructures`
:class:`dict`-like classes defined in ``django.utils.datastructures``
behave likewise in Python 3.
six_ provides compatibility functions to work around this change:

View File

@ -3,140 +3,13 @@ Tests for stuff in django.utils.datastructures.
"""
import copy
import pickle
from django.test import SimpleTestCase, ignore_warnings
from django.test import SimpleTestCase
from django.utils.datastructures import (DictWrapper, ImmutableList,
MultiValueDict, MultiValueDictKeyError, OrderedSet, SortedDict)
from django.utils.deprecation import RemovedInDjango19Warning
MultiValueDict, MultiValueDictKeyError, OrderedSet)
from django.utils import six
@ignore_warnings(category=RemovedInDjango19Warning)
class SortedDictTests(SimpleTestCase):
def setUp(self):
super(SortedDictTests, self).setUp()
self.d1 = SortedDict()
self.d1[7] = 'seven'
self.d1[1] = 'one'
self.d1[9] = 'nine'
self.d2 = SortedDict()
self.d2[1] = 'one'
self.d2[9] = 'nine'
self.d2[0] = 'nil'
self.d2[7] = 'seven'
def test_basic_methods(self):
self.assertEqual(list(six.iterkeys(self.d1)), [7, 1, 9])
self.assertEqual(list(six.itervalues(self.d1)), ['seven', 'one', 'nine'])
self.assertEqual(list(six.iteritems(self.d1)), [(7, 'seven'), (1, 'one'), (9, 'nine')])
def test_overwrite_ordering(self):
""" Overwriting an item keeps its place. """
self.d1[1] = 'ONE'
self.assertEqual(list(six.itervalues(self.d1)), ['seven', 'ONE', 'nine'])
def test_append_items(self):
""" New items go to the end. """
self.d1[0] = 'nil'
self.assertEqual(list(six.iterkeys(self.d1)), [7, 1, 9, 0])
def test_delete_and_insert(self):
"""
Deleting an item, then inserting the same key again will place it
at the end.
"""
del self.d2[7]
self.assertEqual(list(six.iterkeys(self.d2)), [1, 9, 0])
self.d2[7] = 'lucky number 7'
self.assertEqual(list(six.iterkeys(self.d2)), [1, 9, 0, 7])
if six.PY2:
def test_change_keys(self):
"""
Changing the keys won't do anything, it's only a copy of the
keys dict.
This test doesn't make sense under Python 3 because keys is
an iterator.
"""
k = self.d2.keys()
k.remove(9)
self.assertEqual(self.d2.keys(), [1, 9, 0, 7])
def test_init_keys(self):
"""
Initialising a SortedDict with two keys will just take the first one.
A real dict will actually take the second value so we will too, but
we'll keep the ordering from the first key found.
"""
tuples = ((2, 'two'), (1, 'one'), (2, 'second-two'))
d = SortedDict(tuples)
self.assertEqual(list(six.iterkeys(d)), [2, 1])
real_dict = dict(tuples)
self.assertEqual(sorted(six.itervalues(real_dict)), ['one', 'second-two'])
# Here the order of SortedDict values *is* what we are testing
self.assertEqual(list(six.itervalues(d)), ['second-two', 'one'])
def test_overwrite(self):
self.d1[1] = 'not one'
self.assertEqual(self.d1[1], 'not one')
self.assertEqual(list(six.iterkeys(self.d1)), list(six.iterkeys(self.d1.copy())))
def test_append(self):
self.d1[13] = 'thirteen'
self.assertEqual(
repr(self.d1),
"{7: 'seven', 1: 'one', 9: 'nine', 13: 'thirteen'}"
)
def test_pop(self):
self.assertEqual(self.d1.pop(1, 'missing'), 'one')
self.assertEqual(self.d1.pop(1, 'missing'), 'missing')
# We don't know which item will be popped in popitem(), so we'll
# just check that the number of keys has decreased.
l = len(self.d1)
self.d1.popitem()
self.assertEqual(l - len(self.d1), 1)
def test_dict_equality(self):
d = SortedDict((i, i) for i in range(3))
self.assertEqual(d, {0: 0, 1: 1, 2: 2})
def test_tuple_init(self):
d = SortedDict(((1, "one"), (0, "zero"), (2, "two")))
self.assertEqual(repr(d), "{1: 'one', 0: 'zero', 2: 'two'}")
def test_pickle(self):
self.assertEqual(
pickle.loads(pickle.dumps(self.d1, 2)),
{7: 'seven', 1: 'one', 9: 'nine'}
)
def test_copy(self):
orig = SortedDict(((1, "one"), (0, "zero"), (2, "two")))
copied = copy.copy(orig)
self.assertEqual(list(six.iterkeys(orig)), [1, 0, 2])
self.assertEqual(list(six.iterkeys(copied)), [1, 0, 2])
def test_clear(self):
self.d1.clear()
self.assertEqual(self.d1, {})
self.assertEqual(self.d1.keyOrder, [])
def test_reversed(self):
self.assertEqual(list(self.d1), [7, 1, 9])
self.assertEqual(list(self.d2), [1, 9, 0, 7])
self.assertEqual(list(reversed(self.d1)), [9, 1, 7])
self.assertEqual(list(reversed(self.d2)), [7, 0, 9, 1])
class OrderedSetTests(SimpleTestCase):
def test_bool(self):