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 copy
import warnings
from collections import OrderedDict from collections import OrderedDict
from django.utils import six 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): 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 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. 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`` ``django.utils.dateparse``
========================== ==========================

View File

@ -714,12 +714,12 @@ Data structures
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``django.newforms.forms.SortedDictFromList`` was removed. ``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. a sequence of tuples.
To update your code: 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``. using ``django.newforms.forms.SortedDictFromList``.
2. Because ``django.utils.datastructures.SortedDict.copy`` doesn't 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 As :class:`~collections.OrderedDict` was added to the standard library in
Python 2.7, :class:`~django.utils.datastructures.SortedDict` is no longer Python 2.7, ``SortedDict`` is no longer needed and has been deprecated.
needed and has been deprecated.
Custom SQL location for models package 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 :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 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. behave likewise in Python 3.
six_ provides compatibility functions to work around this change: 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 copy
import pickle
from django.test import SimpleTestCase, ignore_warnings from django.test import SimpleTestCase
from django.utils.datastructures import (DictWrapper, ImmutableList, from django.utils.datastructures import (DictWrapper, ImmutableList,
MultiValueDict, MultiValueDictKeyError, OrderedSet, SortedDict) MultiValueDict, MultiValueDictKeyError, OrderedSet)
from django.utils.deprecation import RemovedInDjango19Warning
from django.utils import six 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): class OrderedSetTests(SimpleTestCase):
def test_bool(self): def test_bool(self):