Skip to content

Commit 4097a92

Browse files
committed
gh-132855: Use overridden custom format for inherited PrettyPrinter
1 parent b99d970 commit 4097a92

File tree

2 files changed

+62
-9
lines changed

2 files changed

+62
-9
lines changed

Lib/pprint.py

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -181,30 +181,51 @@ def _format(self, object, stream, indent, allowance, context, level):
181181
self._recursive = True
182182
self._readable = False
183183
return
184+
185+
# If this is a subclass of PrettyPrinter, force all known
186+
# container types through their pretty-printers so that any
187+
# override of format() applies to their elements.
188+
if type(self) is not PrettyPrinter:
189+
fn = type(object).__repr__
190+
# skip raw repr for str/bytes
191+
if fn in self._dispatch and not isinstance(object, (str, bytes, bytearray)):
192+
context[objid] = 1
193+
self._dispatch[fn](
194+
self, object, stream,
195+
indent, allowance, context, level + 1
196+
)
197+
del context[objid]
198+
return
199+
200+
# fallback to one-line repr + width
184201
rep = self._repr(object, context, level)
185202
max_width = self._width - indent - allowance
186203
if len(rep) > max_width:
187204
p = self._dispatch.get(type(object).__repr__, None)
188-
# Lazy import to improve module import time
189205
from dataclasses import is_dataclass
190206

191207
if p is not None:
192208
context[objid] = 1
193-
p(self, object, stream, indent, allowance, context, level + 1)
209+
p(self, object, stream,
210+
indent, allowance, context, level + 1)
194211
del context[objid]
195212
return
196-
elif (is_dataclass(object) and
197-
not isinstance(object, type) and
198-
object.__dataclass_params__.repr and
199-
# Check dataclass has generated repr method.
200-
hasattr(object.__repr__, "__wrapped__") and
201-
"__create_fn__" in object.__repr__.__wrapped__.__qualname__):
213+
elif (is_dataclass(object)
214+
and not isinstance(object, type)
215+
and object.__dataclass_params__.repr
216+
and hasattr(object.__repr__, "__wrapped__")
217+
and "__create_fn__" in object.__repr__.__wrapped__.__qualname__):
202218
context[objid] = 1
203-
self._pprint_dataclass(object, stream, indent, allowance, context, level + 1)
219+
self._pprint_dataclass(object, stream,
220+
indent, allowance,
221+
context, level + 1)
204222
del context[objid]
205223
return
224+
225+
# write the one-line repr
206226
stream.write(rep)
207227

228+
208229
def _pprint_dataclass(self, object, stream, indent, allowance, context, level):
209230
# Lazy import to improve module import time
210231
from dataclasses import fields as dataclass_fields

Lib/test/test_pprint.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,6 +1136,38 @@ def format(self, object, context, maxlevels, level):
11361136
return pprint.PrettyPrinter.format(
11371137
self, object, context, maxlevels, level)
11381138

1139+
# Issue 132855
1140+
SENTINAL = object()
1141+
class _hashable:
1142+
def __hash__(self):
1143+
return 1
1144+
1145+
HASHABLE_SENTINAL = _hashable()
1146+
class CustomPrettyPrinter(pprint.PrettyPrinter):
1147+
def format(self, obj, context, maxlevels, level):
1148+
if obj is SENTINAL:
1149+
return "SENTINAL", True, False
1150+
elif obj is HASHABLE_SENTINAL:
1151+
return "HASHABLE_SENTINAL", True, False
1152+
else:
1153+
return super().format(obj, context, maxlevels, level)
1154+
1155+
class CustomPrettyPrinterTest(unittest.TestCase):
1156+
def test_custom_printer(self):
1157+
# Test that the custom printer works as expected
1158+
obj = SENTINAL
1159+
formatted = CustomPrettyPrinter().pformat(obj)
1160+
self.assertEqual(formatted, "SENTINAL")
1161+
1162+
obj = HASHABLE_SENTINAL
1163+
formatted = CustomPrettyPrinter().pformat(obj)
1164+
self.assertEqual(formatted, "HASHABLE_SENTINAL")
1165+
1166+
# Test that the default printer works as expected
1167+
obj = object()
1168+
formatted = pprint.pformat(obj)
1169+
self.assertNotEqual(formatted, "SENTINAL")
1170+
self.assertNotEqual(formatted, "HASHABLE_SENTINAL")
11391171

11401172
if __name__ == "__main__":
11411173
unittest.main()

0 commit comments

Comments
 (0)