Raymond-Hettingers-MacBook-Pro:py27 raymondhettinger$ cat svn-commit.tmp

Backport r87594 r87611 and r87612 so that OrderedDict subclassing behavior
better matches dict subclassing (i.e. adding __missing__ works and
extending/overriding the update() methods doesn't break __init__()).
This commit is contained in:
Raymond Hettinger 2011-01-02 01:03:26 +00:00
parent fe0263d36f
commit 8ebebd8f7e
3 changed files with 51 additions and 5 deletions

View File

@ -43,7 +43,7 @@ def _recursive_repr(user_function):
### OrderedDict ### OrderedDict
################################################################################ ################################################################################
class OrderedDict(dict, MutableMapping): class OrderedDict(dict):
'Dictionary that remembers insertion order' 'Dictionary that remembers insertion order'
# An inherited dict maps keys to values. # An inherited dict maps keys to values.
# The inherited dict provides __getitem__, __len__, __contains__, and get. # The inherited dict provides __getitem__, __len__, __contains__, and get.
@ -71,7 +71,7 @@ class OrderedDict(dict, MutableMapping):
NEXT = 1 NEXT = 1
root[PREV] = root[NEXT] = root root[PREV] = root[NEXT] = root
self.__map = {} self.__map = {}
self.update(*args, **kwds) self.__update(*args, **kwds)
def __setitem__(self, key, value, PREV=0, NEXT=1, dict_setitem=dict.__setitem__): def __setitem__(self, key, value, PREV=0, NEXT=1, dict_setitem=dict.__setitem__):
'od.__setitem__(i, y) <==> od[i]=y' 'od.__setitem__(i, y) <==> od[i]=y'
@ -134,9 +134,7 @@ class OrderedDict(dict, MutableMapping):
pass pass
dict.clear(self) dict.clear(self)
setdefault = MutableMapping.setdefault update = __update = MutableMapping.update
update = MutableMapping.update
pop = MutableMapping.pop
keys = MutableMapping.keys keys = MutableMapping.keys
values = MutableMapping.values values = MutableMapping.values
items = MutableMapping.items items = MutableMapping.items
@ -157,6 +155,24 @@ class OrderedDict(dict, MutableMapping):
"od.viewitems() -> a set-like object providing a view on od's items" "od.viewitems() -> a set-like object providing a view on od's items"
return ItemsView(self) return ItemsView(self)
__marker = object()
def pop(self, key, default=__marker):
if key in self:
result = self[key]
del self[key]
return result
if default is self.__marker:
raise KeyError(key)
return default
def setdefault(self, key, default=None):
'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
if key in self:
return self[key]
self[key] = default
return default
def popitem(self, last=True): def popitem(self, last=True):
'''od.popitem() -> (k, v), return and remove a (key, value) pair. '''od.popitem() -> (k, v), return and remove a (key, value) pair.
Pairs are returned in LIFO order if last is true or FIFO order if false. Pairs are returned in LIFO order if last is true or FIFO order if false.

View File

@ -812,6 +812,10 @@ class TestOrderedDict(unittest.TestCase):
self.assertEqual(list(d.items()), self.assertEqual(list(d.items()),
[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)]) [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)])
def test_abc(self):
self.assertIsInstance(OrderedDict(), MutableMapping)
self.assertTrue(issubclass(OrderedDict, MutableMapping))
def test_clear(self): def test_clear(self):
pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
shuffle(pairs) shuffle(pairs)
@ -873,6 +877,17 @@ class TestOrderedDict(unittest.TestCase):
self.assertEqual(len(od), 0) self.assertEqual(len(od), 0)
self.assertEqual(od.pop(k, 12345), 12345) self.assertEqual(od.pop(k, 12345), 12345)
# make sure pop still works when __missing__ is defined
class Missing(OrderedDict):
def __missing__(self, key):
return 0
m = Missing(a=1)
self.assertEqual(m.pop('b', 5), 5)
self.assertEqual(m.pop('a', 6), 1)
self.assertEqual(m.pop('a', 6), 6)
with self.assertRaises(KeyError):
m.pop('a')
def test_equality(self): def test_equality(self):
pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
shuffle(pairs) shuffle(pairs)
@ -956,6 +971,12 @@ class TestOrderedDict(unittest.TestCase):
# make sure 'x' is added to the end # make sure 'x' is added to the end
self.assertEqual(list(od.items())[-1], ('x', 10)) self.assertEqual(list(od.items())[-1], ('x', 10))
# make sure setdefault still works when __missing__ is defined
class Missing(OrderedDict):
def __missing__(self, key):
return 0
self.assertEqual(Missing().setdefault(5, 9), 9)
def test_reinsert(self): def test_reinsert(self):
# Given insert a, insert b, delete a, re-insert a, # Given insert a, insert b, delete a, re-insert a,
# verify that a is now later than b. # verify that a is now later than b.
@ -973,6 +994,13 @@ class TestOrderedDict(unittest.TestCase):
self.assertEqual(list(od.viewvalues()), [None for k in s]) self.assertEqual(list(od.viewvalues()), [None for k in s])
self.assertEqual(list(od.viewitems()), [(k, None) for k in s]) self.assertEqual(list(od.viewitems()), [(k, None) for k in s])
def test_override_update(self):
# Verify that subclasses can override update() without breaking __init__()
class MyOD(OrderedDict):
def update(self, *args, **kwds):
raise Exception()
items = [('a', 1), ('c', 3), ('b', 2)]
self.assertEqual(list(MyOD(items).items()), items)
class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol): class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol):
type2test = OrderedDict type2test = OrderedDict

View File

@ -22,6 +22,8 @@ Core and Builtins
Library Library
------- -------
- Subclasses of collections.OrderedDict now work correctly with __missing__.
- Issue 10753 - Characters ';','=' and ',' in the PATH_INFO environment - Issue 10753 - Characters ';','=' and ',' in the PATH_INFO environment
variable won't be quoted when the URI is constructed by the wsgiref.util 's variable won't be quoted when the URI is constructed by the wsgiref.util 's
request_uri method. According to RFC 3986, these characters can be a part of request_uri method. According to RFC 3986, these characters can be a part of