Issue #9826: Handle recursive repr in collections.OrderedDict.

This commit is contained in:
Raymond Hettinger 2010-09-12 05:28:42 +00:00
parent 22450c2aee
commit 69976a7fbe
3 changed files with 22 additions and 4 deletions

View file

@ -43,6 +43,7 @@ class OrderedDict(dict, MutableMapping):
''' '''
if len(args) > 1: if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d' % len(args)) raise TypeError('expected at most 1 arguments, got %d' % len(args))
self.__in_repr = False # detects recursive repr
try: try:
self.__root self.__root
except AttributeError: except AttributeError:
@ -100,10 +101,10 @@ class OrderedDict(dict, MutableMapping):
def __reduce__(self): def __reduce__(self):
'Return state information for pickling' 'Return state information for pickling'
items = [[k, self[k]] for k in self] items = [[k, self[k]] for k in self]
tmp = self.__map, self.__root tmp = self.__map, self.__root, self.__in_repr
del self.__map, self.__root del self.__map, self.__root, self.__in_repr
inst_dict = vars(self).copy() inst_dict = vars(self).copy()
self.__map, self.__root = tmp self.__map, self.__root, self.__in_repr = tmp
if inst_dict: if inst_dict:
return (self.__class__, (items,), inst_dict) return (self.__class__, (items,), inst_dict)
return self.__class__, (items,) return self.__class__, (items,)
@ -128,9 +129,16 @@ class OrderedDict(dict, MutableMapping):
def __repr__(self): def __repr__(self):
'od.__repr__() <==> repr(od)' 'od.__repr__() <==> repr(od)'
if self.__in_repr:
return '...'
if not self: if not self:
return '%s()' % (self.__class__.__name__,) return '%s()' % (self.__class__.__name__,)
return '%s(%r)' % (self.__class__.__name__, list(self.items())) self.__in_repr = True
try:
result = '%s(%r)' % (self.__class__.__name__, list(self.items()))
finally:
self.__in_repr = False
return result
def copy(self): def copy(self):
'od.copy() -> a shallow copy of od' 'od.copy() -> a shallow copy of od'

View file

@ -908,6 +908,13 @@ class TestOrderedDict(unittest.TestCase):
self.assertEqual(eval(repr(od)), od) self.assertEqual(eval(repr(od)), od)
self.assertEqual(repr(OrderedDict()), "OrderedDict()") self.assertEqual(repr(OrderedDict()), "OrderedDict()")
def test_repr_recursive(self):
# See issue #9826
od = OrderedDict.fromkeys('abc')
od['x'] = od
self.assertEqual(repr(od),
"OrderedDict([('a', None), ('b', None), ('c', None), ('x', ...)])")
def test_setdefault(self): def test_setdefault(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)

View file

@ -122,6 +122,9 @@ Library
to fetch the original errno, or to filter timeout errors. Now the to fetch the original errno, or to filter timeout errors. Now the
original error is re-raised. original error is re-raised.
- Issue #9826: OrderedDict.__repr__ can now handle self-referential
values: d['x'] = d.
- Issue #9758: When fcntl.ioctl() was called with mutable_flag set to True, - Issue #9758: When fcntl.ioctl() was called with mutable_flag set to True,
and the passed buffer was exactly 1024 bytes long, the buffer wouldn't and the passed buffer was exactly 1024 bytes long, the buffer wouldn't
be updated back after the system call. Original patch by Brian Brazil. be updated back after the system call. Original patch by Brian Brazil.