diff --git a/Lib/pprint.py b/Lib/pprint.py index 16d8eae57ff..19b9661d8ec 100644 --- a/Lib/pprint.py +++ b/Lib/pprint.py @@ -90,9 +90,9 @@ class PrettyPrinter: """ indent = int(indent) width = int(width) - assert indent >= 0 + assert indent >= 0, "indent must be >= 0" assert depth is None or depth > 0, "depth must be > 0" - assert width + assert width, "width must be != 0" self._depth = depth self._indent_per_level = indent self._width = width @@ -130,7 +130,8 @@ class PrettyPrinter: write = stream.write if sepLines: - if typ is dict: + r = typ.__repr__ + if issubclass(typ, dict) and r is dict.__repr__: write('{') if self._indent_per_level > 1: write((self._indent_per_level - 1) * ' ') @@ -157,8 +158,9 @@ class PrettyPrinter: write('}') return - if typ is list or typ is tuple: - if typ is list: + if (issubclass(typ, list) and r is list.__repr__) or \ + (issubclass(typ, tuple) and r is tuple.__repr__): + if issubclass(typ, list): write('[') endchar = ']' else: @@ -179,7 +181,7 @@ class PrettyPrinter: allowance + 1, context, level) indent = indent - self._indent_per_level del context[objid] - if typ is tuple and length == 1: + if issubclass(typ, tuple) and length == 1: write(',') write(endchar) return @@ -226,7 +228,8 @@ def _safe_repr(object, context, maxlevels, level): write(qget(char, `char`[1:-1])) return ("%s%s%s" % (closure, sio.getvalue(), closure)), True, False - if typ is dict: + r = typ.__repr__ + if issubclass(typ, dict) and r is dict.__repr__: if not object: return "{}", True, False objid = _id(object) @@ -251,8 +254,9 @@ def _safe_repr(object, context, maxlevels, level): del context[objid] return "{%s}" % _commajoin(components), readable, recursive - if typ is list or typ is tuple: - if typ is list: + if (issubclass(typ, list) and r is list.__repr__) or \ + (issubclass(typ, tuple) and r is tuple.__repr__): + if issubclass(typ, list): if not object: return "[]", True, False format = "[%s]" diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py index 0e6559d6b5f..d66b78ac7db 100644 --- a/Lib/test/test_pprint.py +++ b/Lib/test/test_pprint.py @@ -8,6 +8,22 @@ except NameError: def uni(x): return x +# list, tuple and dict subclasses that do or don't overwrite __repr__ +class list2(list): + pass +class list3(list): + def __repr__(self): + return list.__repr__(self) +class tuple2(tuple): + pass +class tuple3(tuple): + def __repr__(self): + return tuple.__repr__(self) +class dict2(dict): + pass +class dict3(dict): + def __repr__(self): + return dict.__repr__(self) class QueryTestCase(unittest.TestCase): @@ -84,11 +100,20 @@ class QueryTestCase(unittest.TestCase): "expected not isreadable for " + `unreadable`) def test_same_as_repr(self): - # Simple objects and small containers that should be same as repr() + # Simple objects, small containers and classes that overwrite __repr__ + # For those the result should be the same as repr() verify = self.assert_ - for simple in (0, 0L, 0+0j, 0.0, "", uni(""), (), [], {}, verify, pprint, + for simple in (0, 0L, 0+0j, 0.0, "", uni(""), + (), tuple2(), tuple3(), + [], list2(), list3(), + {}, dict2(), dict3(), + verify, pprint, -6, -6L, -6-6j, -1.5, "x", uni("x"), (3,), [3], {3: 6}, (1,2), [3,4], {5: 6, 7: 8}, + tuple2((1,2)), tuple3((1,2)), tuple3(range(100)), + [3,4], list2([3,4]), list3([3,4]), list3(range(100)), + {5: 6, 7: 8}, dict2({5: 6, 7: 8}), dict3({5: 6, 7: 8}), + dict3([(x,x) for x in range(100)]), {"xy\tab\n": (3,), 5: [[]], (): {}}, range(10, -11, -1) ): @@ -99,7 +124,6 @@ class QueryTestCase(unittest.TestCase): verify(native == got, "expected %s got %s from pprint.%s" % (native, got, function)) - def test_basic_line_wrap(self): # verify basic line-wrapping operation o = {'RPM_cal': 0, @@ -117,7 +141,18 @@ class QueryTestCase(unittest.TestCase): 'main_code_runtime_us': 0, 'read_io_runtime_us': 0, 'write_io_runtime_us': 43690}""" - self.assertEqual(pprint.pformat(o), exp) + for type in [dict, dict2]: + self.assertEqual(pprint.pformat(type(o)), exp) + + o = range(100) + exp = '[%s]' % ',\n '.join(map(str, o)) + for type in [list, list2]: + self.assertEqual(pprint.pformat(type(o)), exp) + + o = tuple(range(100)) + exp = '(%s)' % ',\n '.join(map(str, o)) + for type in [tuple, tuple2]: + self.assertEqual(pprint.pformat(type(o)), exp) def test_subclassing(self): o = {'names with spaces': 'should be presented using repr()', diff --git a/Misc/NEWS b/Misc/NEWS index a7cefffe5d1..c21a6c611b7 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -170,6 +170,9 @@ Extension modules Library ------- +- Patch #750542: pprint now will pretty print subclasses of list, tuple + and dict too, as long as they don't overwrite __repr__(). + - Bug #848614: distutils' msvccompiler fails to find the MSVC6 compiler because of incomplete registry entries.