diff --git a/Lib/pprint.py b/Lib/pprint.py index dc0953cec67a58..e0dc28fbc7a065 100644 --- a/Lib/pprint.py +++ b/Lib/pprint.py @@ -181,6 +181,23 @@ def _format(self, object, stream, indent, allowance, context, level): self._recursive = True self._readable = False return + + # If this is a subclass of PrettyPrinter, force all known + # container types through their pretty-printers so that any + # override of format() applies to their elements. + if type(self) is not PrettyPrinter: + fn = type(object).__repr__ + # skip raw repr for str/bytes + if fn in self._dispatch and not isinstance(object, (str, bytes, bytearray)): + context[objid] = 1 + self._dispatch[fn]( + self, object, stream, + indent, allowance, context, level + 1 + ) + del context[objid] + return + + # fallback to one-line repr + width rep = self._repr(object, context, level) max_width = self._width - indent - allowance if len(rep) > max_width: @@ -203,6 +220,7 @@ def _format(self, object, stream, indent, allowance, context, level): self._pprint_dataclass(object, stream, indent, allowance, context, level + 1) del context[objid] return + stream.write(rep) def _pprint_dataclass(self, object, stream, indent, allowance, context, level): diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py index dfbc2a06e7346f..5adb43790ba612 100644 --- a/Lib/test/test_pprint.py +++ b/Lib/test/test_pprint.py @@ -1136,6 +1136,38 @@ def format(self, object, context, maxlevels, level): return pprint.PrettyPrinter.format( self, object, context, maxlevels, level) +# Issue 132855 +SENTINAL = object() +class _hashable: + def __hash__(self): + return 1 + +HASHABLE_SENTINAL = _hashable() +class CustomPrettyPrinter(pprint.PrettyPrinter): + def format(self, obj, context, maxlevels, level): + if obj is SENTINAL: + return "SENTINAL", True, False + elif obj is HASHABLE_SENTINAL: + return "HASHABLE_SENTINAL", True, False + else: + return super().format(obj, context, maxlevels, level) + +class CustomPrettyPrinterTest(unittest.TestCase): + def test_custom_printer(self): + # Test that the custom printer works as expected + obj = SENTINAL + formatted = CustomPrettyPrinter().pformat(obj) + self.assertEqual(formatted, "SENTINAL") + + obj = HASHABLE_SENTINAL + formatted = CustomPrettyPrinter().pformat(obj) + self.assertEqual(formatted, "HASHABLE_SENTINAL") + + # Test that the default printer works as expected + obj = object() + formatted = pprint.pformat(obj) + self.assertNotEqual(formatted, "SENTINAL") + self.assertNotEqual(formatted, "HASHABLE_SENTINAL") if __name__ == "__main__": unittest.main()