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

Irit Katriel webhook-mailer at python.org
Sun Aug 30 13:29:58 EDT 2020


https://github.com/python/cpython/commit/582f13786bb75c73d609790967fea03a5b50148a
commit: 582f13786bb75c73d609790967fea03a5b50148a
branch: master
author: Irit Katriel <iritkatriel at yahoo.com>
committer: GitHub <noreply at github.com>
date: 2020-08-30T20:29:53+03:00
summary:

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

Co-authored-by: Palak Kumar Jha

files:
A Misc/NEWS.d/next/Library/2020-08-15-18-17-21.bpo-39994.dOgPOh.rst
M Lib/pprint.py
M Lib/test/test_pprint.py
M Misc/ACKS

diff --git a/Lib/pprint.py b/Lib/pprint.py
index 7c1118a484b26..213998e3491ef 100644
--- a/Lib/pprint.py
+++ b/Lib/pprint.py
@@ -176,12 +176,6 @@ def _format(self, object, stream, indent, allowance, context, level):
                 p(self, object, stream, indent, allowance, context, level + 1)
                 del context[objid]
                 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)
 
     _dispatch = {}
diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py
index cf3e4f093b16e..8ee18e8fef84f 100644
--- a/Lib/test/test_pprint.py
+++ b/Lib/test/test_pprint.py
@@ -18,6 +18,10 @@ class list3(list):
     def __repr__(self):
         return list.__repr__(self)
 
+class list_custom_repr(list):
+    def __repr__(self):
+        return '*'*len(list.__repr__(self))
+
 class tuple2(tuple):
     pass
 
@@ -25,6 +29,10 @@ class tuple3(tuple):
     def __repr__(self):
         return tuple.__repr__(self)
 
+class tuple_custom_repr(tuple):
+    def __repr__(self):
+        return '*'*len(tuple.__repr__(self))
+
 class set2(set):
     pass
 
@@ -32,6 +40,10 @@ class set3(set):
     def __repr__(self):
         return set.__repr__(self)
 
+class set_custom_repr(set):
+    def __repr__(self):
+        return '*'*len(set.__repr__(self))
+
 class frozenset2(frozenset):
     pass
 
@@ -39,6 +51,10 @@ class frozenset3(frozenset):
     def __repr__(self):
         return frozenset.__repr__(self)
 
+class frozenset_custom_repr(frozenset):
+    def __repr__(self):
+        return '*'*len(frozenset.__repr__(self))
+
 class dict2(dict):
     pass
 
@@ -46,6 +62,10 @@ class dict3(dict):
     def __repr__(self):
         return dict.__repr__(self)
 
+class dict_custom_repr(dict):
+    def __repr__(self):
+        return '*'*len(dict.__repr__(self))
+
 class Unorderable:
     def __repr__(self):
         return str(id(self))
@@ -155,7 +175,8 @@ def test_unreadable(self):
                              "expected not isreadable for %r" % (unreadable,))
 
     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().
         # Ahem.  The docs don't say anything about that -- this appears to
         # be testing an implementation quirk.  Starting in Python 2.5, it's
@@ -187,6 +208,32 @@ def test_same_as_repr(self):
                              .replace('\n', ' '), 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):
         # verify basic line-wrapping operation
         o = {'RPM_cal': 0,
diff --git a/Misc/ACKS b/Misc/ACKS
index 1599b09c692b7..a2cdeb8504059 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -856,6 +856,7 @@ Per Øyvind Karlsen
 Anton Kasyanov
 Lou Kates
 Makoto Kato
+Irit Katriel
 Hiroaki Kawai
 Dmitry Kazakov
 Brian Kearns
diff --git a/Misc/NEWS.d/next/Library/2020-08-15-18-17-21.bpo-39994.dOgPOh.rst b/Misc/NEWS.d/next/Library/2020-08-15-18-17-21.bpo-39994.dOgPOh.rst
new file mode 100644
index 0000000000000..46876c15ea199
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-08-15-18-17-21.bpo-39994.dOgPOh.rst
@@ -0,0 +1 @@
+Fixed pprint's handling of dict subclasses that override __repr__.



More information about the Python-checkins mailing list