bpo-39994: Fix pprint handling of dict subclasses that override __repr__ (GH-21892)

Co-authored-by: Palak Kumar Jha
This commit is contained in:
Irit Katriel 2020-08-30 18:29:53 +01:00 committed by GitHub
parent 92c38164a4
commit 582f13786b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 50 additions and 7 deletions

View File

@ -176,12 +176,6 @@ class PrettyPrinter:
p(self, object, stream, indent, allowance, context, level + 1) p(self, object, stream, indent, allowance, context, level + 1)
del context[objid] del context[objid]
return return
elif isinstance(object, dict):
context[objid] = 1
self._pprint_dict(object, stream, indent, allowance,
context, level + 1)
del context[objid]
return
stream.write(rep) stream.write(rep)
_dispatch = {} _dispatch = {}

View File

@ -18,6 +18,10 @@ class list3(list):
def __repr__(self): def __repr__(self):
return list.__repr__(self) return list.__repr__(self)
class list_custom_repr(list):
def __repr__(self):
return '*'*len(list.__repr__(self))
class tuple2(tuple): class tuple2(tuple):
pass pass
@ -25,6 +29,10 @@ class tuple3(tuple):
def __repr__(self): def __repr__(self):
return tuple.__repr__(self) return tuple.__repr__(self)
class tuple_custom_repr(tuple):
def __repr__(self):
return '*'*len(tuple.__repr__(self))
class set2(set): class set2(set):
pass pass
@ -32,6 +40,10 @@ class set3(set):
def __repr__(self): def __repr__(self):
return set.__repr__(self) return set.__repr__(self)
class set_custom_repr(set):
def __repr__(self):
return '*'*len(set.__repr__(self))
class frozenset2(frozenset): class frozenset2(frozenset):
pass pass
@ -39,6 +51,10 @@ class frozenset3(frozenset):
def __repr__(self): def __repr__(self):
return frozenset.__repr__(self) return frozenset.__repr__(self)
class frozenset_custom_repr(frozenset):
def __repr__(self):
return '*'*len(frozenset.__repr__(self))
class dict2(dict): class dict2(dict):
pass pass
@ -46,6 +62,10 @@ class dict3(dict):
def __repr__(self): def __repr__(self):
return dict.__repr__(self) return dict.__repr__(self)
class dict_custom_repr(dict):
def __repr__(self):
return '*'*len(dict.__repr__(self))
class Unorderable: class Unorderable:
def __repr__(self): def __repr__(self):
return str(id(self)) return str(id(self))
@ -155,7 +175,8 @@ class QueryTestCase(unittest.TestCase):
"expected not isreadable for %r" % (unreadable,)) "expected not isreadable for %r" % (unreadable,))
def test_same_as_repr(self): def test_same_as_repr(self):
# Simple objects, small containers and classes that overwrite __repr__ # Simple objects, small containers and classes that override __repr__
# to directly call super's __repr__.
# For those the result should be the same as repr(). # For those the result should be the same as repr().
# Ahem. The docs don't say anything about that -- this appears to # Ahem. The docs don't say anything about that -- this appears to
# be testing an implementation quirk. Starting in Python 2.5, it's # be testing an implementation quirk. Starting in Python 2.5, it's
@ -187,6 +208,32 @@ class QueryTestCase(unittest.TestCase):
.replace('\n', ' '), native) .replace('\n', ' '), native)
self.assertEqual(pprint.saferepr(simple), native) self.assertEqual(pprint.saferepr(simple), native)
def test_container_repr_override_called(self):
N = 1000
# Ensure that __repr__ override is called for subclasses of containers
for cont in (list_custom_repr(),
list_custom_repr([1,2,3]),
list_custom_repr(range(N)),
tuple_custom_repr(),
tuple_custom_repr([1,2,3]),
tuple_custom_repr(range(N)),
set_custom_repr(),
set_custom_repr([1,2,3]),
set_custom_repr(range(N)),
frozenset_custom_repr(),
frozenset_custom_repr([1,2,3]),
frozenset_custom_repr(range(N)),
dict_custom_repr(),
dict_custom_repr({5: 6}),
dict_custom_repr(zip(range(N),range(N))),
):
native = repr(cont)
expected = '*' * len(native)
self.assertEqual(pprint.pformat(cont), expected)
self.assertEqual(pprint.pformat(cont, width=1, indent=0), expected)
self.assertEqual(pprint.saferepr(cont), expected)
def test_basic_line_wrap(self): def test_basic_line_wrap(self):
# verify basic line-wrapping operation # verify basic line-wrapping operation
o = {'RPM_cal': 0, o = {'RPM_cal': 0,

View File

@ -856,6 +856,7 @@ Per Øyvind Karlsen
Anton Kasyanov Anton Kasyanov
Lou Kates Lou Kates
Makoto Kato Makoto Kato
Irit Katriel
Hiroaki Kawai Hiroaki Kawai
Dmitry Kazakov Dmitry Kazakov
Brian Kearns Brian Kearns

View File

@ -0,0 +1 @@
Fixed pprint's handling of dict subclasses that override __repr__.