blob: b45cfdd99a8e11a05f151cd700e05e808a8f8434 [file] [log] [blame]
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001# Author: Fred L. Drake, Jr.
Fred Drake3e5e6612001-10-09 20:53:48 +00002# fdrake@acm.org
Guido van Rossum5e92aff1997-04-16 00:49:59 +00003#
4# This is a simple little module I wrote to make life easier. I didn't
5# see anything quite like it in the library, though I may have overlooked
6# something. I wrote this when I was trying to read some heavily nested
Thomas Wouters7e474022000-07-16 12:04:32 +00007# tuples with fairly non-descriptive content. This is modeled very much
Guido van Rossum5e92aff1997-04-16 00:49:59 +00008# after Lisp/Scheme - style pretty-printing of lists. If you find it
9# useful, thank small children who sleep at night.
10
11"""Support to pretty-print lists, tuples, & dictionaries recursively.
12
13Very simple, but useful, especially in debugging data structures.
14
Fred Drakea89fda01997-04-16 16:59:30 +000015Classes
16-------
17
18PrettyPrinter()
19 Handle pretty-printing operations onto a stream using a configured
20 set of formatting parameters.
21
Guido van Rossum5e92aff1997-04-16 00:49:59 +000022Functions
23---------
24
25pformat()
26 Format a Python object into a pretty-printed representation.
27
28pprint()
Skip Montanaro2dc0c132004-05-14 16:31:56 +000029 Pretty-print a Python object to a stream [default is sys.stdout].
Guido van Rossum5e92aff1997-04-16 00:49:59 +000030
Fred Drakea89fda01997-04-16 16:59:30 +000031saferepr()
32 Generate a 'standard' repr()-like value, but protect against recursive
33 data structures.
Guido van Rossum5e92aff1997-04-16 00:49:59 +000034
35"""
36
Serhiy Storchakaaa4c36f2015-03-26 08:51:33 +020037import collections as _collections
Antoine Pitrou64c16c32013-03-23 20:30:39 +010038import re
Fred Drake397b6152002-12-31 07:14:18 +000039import sys as _sys
Serhiy Storchaka87eb4822015-03-24 19:31:50 +020040import types as _types
Guido van Rossum34d19282007-08-09 01:03:29 +000041from io import StringIO as _StringIO
Guido van Rossum5e92aff1997-04-16 00:49:59 +000042
Skip Montanaroc62c81e2001-02-12 02:00:42 +000043__all__ = ["pprint","pformat","isreadable","isrecursive","saferepr",
Rémi Lapeyre96831c72019-03-22 18:22:20 +010044 "PrettyPrinter", "pp"]
Guido van Rossum5e92aff1997-04-16 00:49:59 +000045
Fred Drake49cc01e2001-11-01 17:50:38 +000046
Serhiy Storchaka7c411a42013-10-02 11:56:18 +030047def pprint(object, stream=None, indent=1, width=80, depth=None, *,
sblondon3ba3d512021-03-24 09:23:20 +010048 compact=False, sort_dicts=True, underscore_numbers=False):
Skip Montanaro2dc0c132004-05-14 16:31:56 +000049 """Pretty-print a Python object to a stream [default is sys.stdout]."""
Walter Dörwaldc8de4582003-12-03 20:26:05 +000050 printer = PrettyPrinter(
Serhiy Storchaka7c411a42013-10-02 11:56:18 +030051 stream=stream, indent=indent, width=width, depth=depth,
sblondon3ba3d512021-03-24 09:23:20 +010052 compact=compact, sort_dicts=sort_dicts, underscore_numbers=False)
Fred Drakea89fda01997-04-16 16:59:30 +000053 printer.pprint(object)
Guido van Rossum5e92aff1997-04-16 00:49:59 +000054
Rémi Lapeyre96831c72019-03-22 18:22:20 +010055def pformat(object, indent=1, width=80, depth=None, *,
sblondon3ba3d512021-03-24 09:23:20 +010056 compact=False, sort_dicts=True, underscore_numbers=False):
Fred Drakea89fda01997-04-16 16:59:30 +000057 """Format a Python object into a pretty-printed representation."""
Serhiy Storchaka7c411a42013-10-02 11:56:18 +030058 return PrettyPrinter(indent=indent, width=width, depth=depth,
sblondon3ba3d512021-03-24 09:23:20 +010059 compact=compact, sort_dicts=sort_dicts,
60 underscore_numbers=underscore_numbers).pformat(object)
Rémi Lapeyre96831c72019-03-22 18:22:20 +010061
62def pp(object, *args, sort_dicts=False, **kwargs):
63 """Pretty-print a Python object"""
64 pprint(object, *args, sort_dicts=sort_dicts, **kwargs)
Guido van Rossum5e92aff1997-04-16 00:49:59 +000065
Fred Drakea89fda01997-04-16 16:59:30 +000066def saferepr(object):
67 """Version of repr() which can handle recursive data structures."""
Irit Katrielff420f02020-11-23 13:31:31 +000068 return PrettyPrinter()._safe_repr(object, {}, None, 0)[0]
Guido van Rossum5e92aff1997-04-16 00:49:59 +000069
Tim Petersa814db52001-05-14 07:05:58 +000070def isreadable(object):
71 """Determine if saferepr(object) is readable by eval()."""
Irit Katrielff420f02020-11-23 13:31:31 +000072 return PrettyPrinter()._safe_repr(object, {}, None, 0)[1]
Tim Petersa814db52001-05-14 07:05:58 +000073
74def isrecursive(object):
75 """Determine if object requires a recursive representation."""
Irit Katrielff420f02020-11-23 13:31:31 +000076 return PrettyPrinter()._safe_repr(object, {}, None, 0)[2]
Guido van Rossum5e92aff1997-04-16 00:49:59 +000077
Raymond Hettingera7da1662009-11-19 01:07:05 +000078class _safe_key:
79 """Helper function for key functions when sorting unorderable objects.
80
Serhiy Storchaka6a7b3a72016-04-17 08:32:47 +030081 The wrapped-object will fallback to a Py2.x style comparison for
Raymond Hettingera7da1662009-11-19 01:07:05 +000082 unorderable types (sorting first comparing the type name and then by
83 the obj ids). Does not work recursively, so dict.items() must have
84 _safe_key applied to both the key and the value.
85
86 """
87
88 __slots__ = ['obj']
89
90 def __init__(self, obj):
91 self.obj = obj
92
93 def __lt__(self, other):
Florent Xiclunad6da90f2012-07-21 11:17:38 +020094 try:
Serhiy Storchaka62aa7dc2015-04-06 22:52:44 +030095 return self.obj < other.obj
Florent Xiclunad6da90f2012-07-21 11:17:38 +020096 except TypeError:
Serhiy Storchaka62aa7dc2015-04-06 22:52:44 +030097 return ((str(type(self.obj)), id(self.obj)) < \
98 (str(type(other.obj)), id(other.obj)))
Raymond Hettingera7da1662009-11-19 01:07:05 +000099
100def _safe_tuple(t):
101 "Helper function for comparing 2-tuples"
102 return _safe_key(t[0]), _safe_key(t[1])
103
Fred Drakea89fda01997-04-16 16:59:30 +0000104class PrettyPrinter:
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300105 def __init__(self, indent=1, width=80, depth=None, stream=None, *,
sblondon3ba3d512021-03-24 09:23:20 +0100106 compact=False, sort_dicts=True, underscore_numbers=False):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000107 """Handle pretty printing operations onto a stream using a set of
108 configured parameters.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000109
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000110 indent
111 Number of spaces to indent for each level of nesting.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000112
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000113 width
114 Attempted maximum number of columns in the output.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000115
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000116 depth
117 The maximum depth to print out nested structures.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000118
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000119 stream
120 The desired output stream. If omitted (or false), the standard
121 output stream available at construction will be used.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000122
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300123 compact
124 If true, several items will be combined in one line.
125
Rémi Lapeyre96831c72019-03-22 18:22:20 +0100126 sort_dicts
127 If true, dict keys are sorted.
128
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000129 """
130 indent = int(indent)
131 width = int(width)
Serhiy Storchakaf3fa3082015-03-26 08:43:21 +0200132 if indent < 0:
133 raise ValueError('indent must be >= 0')
134 if depth is not None and depth <= 0:
135 raise ValueError('depth must be > 0')
136 if not width:
137 raise ValueError('width must be != 0')
Fred Drakee6691ef2002-07-08 12:28:06 +0000138 self._depth = depth
139 self._indent_per_level = indent
140 self._width = width
Raymond Hettinger16e3c422002-06-01 16:07:16 +0000141 if stream is not None:
Fred Drakee6691ef2002-07-08 12:28:06 +0000142 self._stream = stream
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000143 else:
Fred Drake397b6152002-12-31 07:14:18 +0000144 self._stream = _sys.stdout
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300145 self._compact = bool(compact)
Rémi Lapeyre96831c72019-03-22 18:22:20 +0100146 self._sort_dicts = sort_dicts
sblondon3ba3d512021-03-24 09:23:20 +0100147 self._underscore_numbers = underscore_numbers
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000148
Fred Drakea89fda01997-04-16 16:59:30 +0000149 def pprint(self, object):
Walter Dörwalde62e9362005-11-11 18:18:51 +0000150 self._format(object, self._stream, 0, 0, {}, 0)
151 self._stream.write("\n")
Fred Drakea89fda01997-04-16 16:59:30 +0000152
153 def pformat(self, object):
Fred Drake397b6152002-12-31 07:14:18 +0000154 sio = _StringIO()
Fred Drakee6691ef2002-07-08 12:28:06 +0000155 self._format(object, sio, 0, 0, {}, 0)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000156 return sio.getvalue()
Fred Drakea89fda01997-04-16 16:59:30 +0000157
Fred Drakee0ffabe1997-07-18 20:42:39 +0000158 def isrecursive(self, object):
Fred Drake397b6152002-12-31 07:14:18 +0000159 return self.format(object, {}, 0, 0)[2]
Fred Drakee0ffabe1997-07-18 20:42:39 +0000160
161 def isreadable(self, object):
Fred Drake397b6152002-12-31 07:14:18 +0000162 s, readable, recursive = self.format(object, {}, 0, 0)
Fred Drakeaee113d2002-04-02 05:08:35 +0000163 return readable and not recursive
Fred Drakee0ffabe1997-07-18 20:42:39 +0000164
Fred Drakee6691ef2002-07-08 12:28:06 +0000165 def _format(self, object, stream, indent, allowance, context, level):
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200166 objid = id(object)
Fred Drake49cc01e2001-11-01 17:50:38 +0000167 if objid in context:
168 stream.write(_recursion(object))
Fred Drakee6691ef2002-07-08 12:28:06 +0000169 self._recursive = True
170 self._readable = False
Fred Drake49cc01e2001-11-01 17:50:38 +0000171 return
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200172 rep = self._repr(object, context, level)
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200173 max_width = self._width - indent - allowance
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200174 if len(rep) > max_width:
175 p = self._dispatch.get(type(object).__repr__, None)
176 if p is not None:
177 context[objid] = 1
178 p(self, object, stream, indent, allowance, context, level + 1)
179 del context[objid]
180 return
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200181 stream.write(rep)
182
183 _dispatch = {}
184
185 def _pprint_dict(self, object, stream, indent, allowance, context, level):
Fred Drake49cc01e2001-11-01 17:50:38 +0000186 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200187 write('{')
188 if self._indent_per_level > 1:
189 write((self._indent_per_level - 1) * ' ')
190 length = len(object)
191 if length:
Rémi Lapeyre96831c72019-03-22 18:22:20 +0100192 if self._sort_dicts:
193 items = sorted(object.items(), key=_safe_tuple)
194 else:
195 items = object.items()
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200196 self._format_dict_items(items, stream, indent, allowance + 1,
197 context, level)
198 write('}')
Fred Drakea89fda01997-04-16 16:59:30 +0000199
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200200 _dispatch[dict.__repr__] = _pprint_dict
Serhiy Storchakaaa4c36f2015-03-26 08:51:33 +0200201
202 def _pprint_ordered_dict(self, object, stream, indent, allowance, context, level):
203 if not len(object):
204 stream.write(repr(object))
205 return
206 cls = object.__class__
207 stream.write(cls.__name__ + '(')
208 self._format(list(object.items()), stream,
209 indent + len(cls.__name__) + 1, allowance + 1,
210 context, level)
211 stream.write(')')
212
213 _dispatch[_collections.OrderedDict.__repr__] = _pprint_ordered_dict
Fred Drakea89fda01997-04-16 16:59:30 +0000214
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200215 def _pprint_list(self, object, stream, indent, allowance, context, level):
216 stream.write('[')
217 self._format_items(object, stream, indent, allowance + 1,
218 context, level)
219 stream.write(']')
Fred Drakea89fda01997-04-16 16:59:30 +0000220
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200221 _dispatch[list.__repr__] = _pprint_list
222
223 def _pprint_tuple(self, object, stream, indent, allowance, context, level):
224 stream.write('(')
225 endchar = ',)' if len(object) == 1 else ')'
226 self._format_items(object, stream, indent, allowance + len(endchar),
227 context, level)
228 stream.write(endchar)
229
230 _dispatch[tuple.__repr__] = _pprint_tuple
231
232 def _pprint_set(self, object, stream, indent, allowance, context, level):
233 if not len(object):
234 stream.write(repr(object))
235 return
236 typ = object.__class__
237 if typ is set:
238 stream.write('{')
239 endchar = '}'
240 else:
241 stream.write(typ.__name__ + '({')
242 endchar = '})'
243 indent += len(typ.__name__) + 1
244 object = sorted(object, key=_safe_key)
245 self._format_items(object, stream, indent, allowance + len(endchar),
246 context, level)
247 stream.write(endchar)
248
249 _dispatch[set.__repr__] = _pprint_set
250 _dispatch[frozenset.__repr__] = _pprint_set
251
252 def _pprint_str(self, object, stream, indent, allowance, context, level):
253 write = stream.write
254 if not len(object):
255 write(repr(object))
256 return
257 chunks = []
258 lines = object.splitlines(True)
259 if level == 1:
260 indent += 1
261 allowance += 1
262 max_width1 = max_width = self._width - indent
263 for i, line in enumerate(lines):
264 rep = repr(line)
265 if i == len(lines) - 1:
266 max_width1 -= allowance
267 if len(rep) <= max_width1:
268 chunks.append(rep)
269 else:
270 # A list of alternating (non-space, space) strings
271 parts = re.findall(r'\S*\s*', line)
272 assert parts
273 assert not parts[-1]
274 parts.pop() # drop empty last part
275 max_width2 = max_width
276 current = ''
277 for j, part in enumerate(parts):
278 candidate = current + part
279 if j == len(parts) - 1 and i == len(lines) - 1:
280 max_width2 -= allowance
281 if len(repr(candidate)) > max_width2:
Serhiy Storchakafe3dc372014-12-20 20:57:15 +0200282 if current:
283 chunks.append(repr(current))
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200284 current = part
285 else:
286 current = candidate
287 if current:
288 chunks.append(repr(current))
289 if len(chunks) == 1:
290 write(rep)
291 return
292 if level == 1:
293 write('(')
294 for i, rep in enumerate(chunks):
295 if i > 0:
296 write('\n' + ' '*indent)
297 write(rep)
298 if level == 1:
299 write(')')
300
301 _dispatch[str.__repr__] = _pprint_str
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000302
Serhiy Storchaka022f2032015-03-24 19:22:37 +0200303 def _pprint_bytes(self, object, stream, indent, allowance, context, level):
304 write = stream.write
305 if len(object) <= 4:
306 write(repr(object))
307 return
308 parens = level == 1
309 if parens:
310 indent += 1
311 allowance += 1
312 write('(')
313 delim = ''
314 for rep in _wrap_bytes_repr(object, self._width - indent, allowance):
315 write(delim)
316 write(rep)
317 if not delim:
318 delim = '\n' + ' '*indent
319 if parens:
320 write(')')
321
322 _dispatch[bytes.__repr__] = _pprint_bytes
323
324 def _pprint_bytearray(self, object, stream, indent, allowance, context, level):
325 write = stream.write
326 write('bytearray(')
327 self._pprint_bytes(bytes(object), stream, indent + 10,
328 allowance + 1, context, level + 1)
329 write(')')
330
331 _dispatch[bytearray.__repr__] = _pprint_bytearray
332
Serhiy Storchaka87eb4822015-03-24 19:31:50 +0200333 def _pprint_mappingproxy(self, object, stream, indent, allowance, context, level):
334 stream.write('mappingproxy(')
335 self._format(object.copy(), stream, indent + 13, allowance + 1,
336 context, level)
337 stream.write(')')
338
339 _dispatch[_types.MappingProxyType.__repr__] = _pprint_mappingproxy
340
Carl Bordum Hansen06a89162019-06-27 01:13:18 +0200341 def _pprint_simplenamespace(self, object, stream, indent, allowance, context, level):
342 if type(object) is _types.SimpleNamespace:
343 # The SimpleNamespace repr is "namespace" instead of the class
344 # name, so we do the same here. For subclasses; use the class name.
345 cls_name = 'namespace'
346 else:
347 cls_name = object.__class__.__name__
348 indent += len(cls_name) + 1
349 delimnl = ',\n' + ' ' * indent
350 items = object.__dict__.items()
351 last_index = len(items) - 1
352
353 stream.write(cls_name + '(')
354 for i, (key, ent) in enumerate(items):
355 stream.write(key)
356 stream.write('=')
357
358 last = i == last_index
359 self._format(ent, stream, indent + len(key) + 1,
360 allowance if last else 1,
361 context, level)
362 if not last:
363 stream.write(delimnl)
364 stream.write(')')
365
366 _dispatch[_types.SimpleNamespace.__repr__] = _pprint_simplenamespace
367
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200368 def _format_dict_items(self, items, stream, indent, allowance, context,
369 level):
370 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200371 indent += self._indent_per_level
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200372 delimnl = ',\n' + ' ' * indent
373 last_index = len(items) - 1
374 for i, (key, ent) in enumerate(items):
375 last = i == last_index
376 rep = self._repr(key, context, level)
377 write(rep)
378 write(': ')
379 self._format(ent, stream, indent + len(rep) + 2,
380 allowance if last else 1,
381 context, level)
382 if not last:
383 write(delimnl)
384
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300385 def _format_items(self, items, stream, indent, allowance, context, level):
386 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200387 indent += self._indent_per_level
388 if self._indent_per_level > 1:
389 write((self._indent_per_level - 1) * ' ')
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300390 delimnl = ',\n' + ' ' * indent
391 delim = ''
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200392 width = max_width = self._width - indent + 1
393 it = iter(items)
394 try:
395 next_ent = next(it)
396 except StopIteration:
397 return
398 last = False
399 while not last:
400 ent = next_ent
401 try:
402 next_ent = next(it)
403 except StopIteration:
404 last = True
405 max_width -= allowance
406 width -= allowance
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300407 if self._compact:
408 rep = self._repr(ent, context, level)
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200409 w = len(rep) + 2
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300410 if width < w:
411 width = max_width
412 if delim:
413 delim = delimnl
414 if width >= w:
415 width -= w
416 write(delim)
417 delim = ', '
418 write(rep)
419 continue
420 write(delim)
421 delim = delimnl
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200422 self._format(ent, stream, indent,
423 allowance if last else 1,
424 context, level)
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300425
Fred Drakee6691ef2002-07-08 12:28:06 +0000426 def _repr(self, object, context, level):
Fred Drakeaee113d2002-04-02 05:08:35 +0000427 repr, readable, recursive = self.format(object, context.copy(),
Fred Drakee6691ef2002-07-08 12:28:06 +0000428 self._depth, level)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000429 if not readable:
Fred Drakee6691ef2002-07-08 12:28:06 +0000430 self._readable = False
Tim Petersa814db52001-05-14 07:05:58 +0000431 if recursive:
Fred Drakee6691ef2002-07-08 12:28:06 +0000432 self._recursive = True
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000433 return repr
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000434
Fred Drakeaee113d2002-04-02 05:08:35 +0000435 def format(self, object, context, maxlevels, level):
436 """Format object for a specific context, returning a string
437 and flags indicating whether the representation is 'readable'
438 and whether the object represents a recursive construct.
439 """
Irit Katrielff420f02020-11-23 13:31:31 +0000440 return self._safe_repr(object, context, maxlevels, level)
Fred Drakeaee113d2002-04-02 05:08:35 +0000441
Serhiy Storchakabedbf962015-05-12 13:35:48 +0300442 def _pprint_default_dict(self, object, stream, indent, allowance, context, level):
443 if not len(object):
444 stream.write(repr(object))
445 return
446 rdf = self._repr(object.default_factory, context, level)
447 cls = object.__class__
448 indent += len(cls.__name__) + 1
449 stream.write('%s(%s,\n%s' % (cls.__name__, rdf, ' ' * indent))
450 self._pprint_dict(object, stream, indent, allowance + 1, context, level)
451 stream.write(')')
452
453 _dispatch[_collections.defaultdict.__repr__] = _pprint_default_dict
454
455 def _pprint_counter(self, object, stream, indent, allowance, context, level):
456 if not len(object):
457 stream.write(repr(object))
458 return
459 cls = object.__class__
460 stream.write(cls.__name__ + '({')
461 if self._indent_per_level > 1:
462 stream.write((self._indent_per_level - 1) * ' ')
463 items = object.most_common()
464 self._format_dict_items(items, stream,
465 indent + len(cls.__name__) + 1, allowance + 2,
466 context, level)
467 stream.write('})')
468
469 _dispatch[_collections.Counter.__repr__] = _pprint_counter
470
471 def _pprint_chain_map(self, object, stream, indent, allowance, context, level):
472 if not len(object.maps):
473 stream.write(repr(object))
474 return
475 cls = object.__class__
476 stream.write(cls.__name__ + '(')
477 indent += len(cls.__name__) + 1
478 for i, m in enumerate(object.maps):
479 if i == len(object.maps) - 1:
480 self._format(m, stream, indent, allowance + 1, context, level)
481 stream.write(')')
482 else:
483 self._format(m, stream, indent, 1, context, level)
484 stream.write(',\n' + ' ' * indent)
485
486 _dispatch[_collections.ChainMap.__repr__] = _pprint_chain_map
487
488 def _pprint_deque(self, object, stream, indent, allowance, context, level):
489 if not len(object):
490 stream.write(repr(object))
491 return
492 cls = object.__class__
493 stream.write(cls.__name__ + '(')
494 indent += len(cls.__name__) + 1
495 stream.write('[')
496 if object.maxlen is None:
497 self._format_items(object, stream, indent, allowance + 2,
498 context, level)
499 stream.write('])')
500 else:
501 self._format_items(object, stream, indent, 2,
502 context, level)
503 rml = self._repr(object.maxlen, context, level)
504 stream.write('],\n%smaxlen=%s)' % (' ' * indent, rml))
505
506 _dispatch[_collections.deque.__repr__] = _pprint_deque
507
508 def _pprint_user_dict(self, object, stream, indent, allowance, context, level):
509 self._format(object.data, stream, indent, allowance, context, level - 1)
510
511 _dispatch[_collections.UserDict.__repr__] = _pprint_user_dict
512
513 def _pprint_user_list(self, object, stream, indent, allowance, context, level):
514 self._format(object.data, stream, indent, allowance, context, level - 1)
515
516 _dispatch[_collections.UserList.__repr__] = _pprint_user_list
517
518 def _pprint_user_string(self, object, stream, indent, allowance, context, level):
519 self._format(object.data, stream, indent, allowance, context, level - 1)
520
521 _dispatch[_collections.UserString.__repr__] = _pprint_user_string
Fred Drakeaee113d2002-04-02 05:08:35 +0000522
Irit Katrielff420f02020-11-23 13:31:31 +0000523 def _safe_repr(self, object, context, maxlevels, level):
524 # Return triple (repr_string, isreadable, isrecursive).
525 typ = type(object)
526 if typ in _builtin_scalars:
527 return repr(object), True, False
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000528
Irit Katrielff420f02020-11-23 13:31:31 +0000529 r = getattr(typ, "__repr__", None)
sblondon3ba3d512021-03-24 09:23:20 +0100530
531 if issubclass(typ, int) and r is int.__repr__:
532 if self._underscore_numbers:
533 return f"{object:_d}", True, False
534 else:
535 return repr(object), True, False
536
Irit Katrielff420f02020-11-23 13:31:31 +0000537 if issubclass(typ, dict) and r is dict.__repr__:
Fred Drake49cc01e2001-11-01 17:50:38 +0000538 if not object:
Irit Katrielff420f02020-11-23 13:31:31 +0000539 return "{}", True, False
540 objid = id(object)
541 if maxlevels and level >= maxlevels:
542 return "{...}", False, objid in context
543 if objid in context:
544 return _recursion(object), False, True
545 context[objid] = 1
546 readable = True
547 recursive = False
548 components = []
549 append = components.append
550 level += 1
551 if self._sort_dicts:
552 items = sorted(object.items(), key=_safe_tuple)
553 else:
554 items = object.items()
555 for k, v in items:
556 krepr, kreadable, krecur = self.format(
557 k, context, maxlevels, level)
558 vrepr, vreadable, vrecur = self.format(
559 v, context, maxlevels, level)
560 append("%s: %s" % (krepr, vrepr))
561 readable = readable and kreadable and vreadable
562 if krecur or vrecur:
563 recursive = True
564 del context[objid]
565 return "{%s}" % ", ".join(components), readable, recursive
Tim Peters88768482001-11-13 21:51:26 +0000566
Irit Katrielff420f02020-11-23 13:31:31 +0000567 if (issubclass(typ, list) and r is list.__repr__) or \
568 (issubclass(typ, tuple) and r is tuple.__repr__):
569 if issubclass(typ, list):
570 if not object:
571 return "[]", True, False
572 format = "[%s]"
573 elif len(object) == 1:
574 format = "(%s,)"
575 else:
576 if not object:
577 return "()", True, False
578 format = "(%s)"
579 objid = id(object)
580 if maxlevels and level >= maxlevels:
581 return format % "...", False, objid in context
582 if objid in context:
583 return _recursion(object), False, True
584 context[objid] = 1
585 readable = True
586 recursive = False
587 components = []
588 append = components.append
589 level += 1
590 for o in object:
591 orepr, oreadable, orecur = self.format(
592 o, context, maxlevels, level)
593 append(orepr)
594 if not oreadable:
595 readable = False
596 if orecur:
597 recursive = True
598 del context[objid]
599 return format % ", ".join(components), readable, recursive
600
601 rep = repr(object)
602 return rep, (rep and not rep.startswith('<')), False
Tim Peters95b3f782001-05-14 18:39:41 +0000603
sblondon3ba3d512021-03-24 09:23:20 +0100604_builtin_scalars = frozenset({str, bytes, bytearray, float, complex,
Serhiy Storchaka8eb1f072015-05-16 21:38:05 +0300605 bool, type(None)})
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000606
Fred Drake49cc01e2001-11-01 17:50:38 +0000607def _recursion(object):
608 return ("<Recursion on %s with id=%s>"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200609 % (type(object).__name__, id(object)))
Fred Drakea89fda01997-04-16 16:59:30 +0000610
Fred Drake49cc01e2001-11-01 17:50:38 +0000611
612def _perfcheck(object=None):
613 import time
614 if object is None:
615 object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
616 p = PrettyPrinter()
Victor Stinner8db5b542018-12-17 11:30:34 +0100617 t1 = time.perf_counter()
Irit Katrielff420f02020-11-23 13:31:31 +0000618 p._safe_repr(object, {}, None, 0, True)
Victor Stinner8db5b542018-12-17 11:30:34 +0100619 t2 = time.perf_counter()
Fred Drake49cc01e2001-11-01 17:50:38 +0000620 p.pformat(object)
Victor Stinner8db5b542018-12-17 11:30:34 +0100621 t3 = time.perf_counter()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000622 print("_safe_repr:", t2 - t1)
623 print("pformat:", t3 - t2)
Fred Drake49cc01e2001-11-01 17:50:38 +0000624
Serhiy Storchaka022f2032015-03-24 19:22:37 +0200625def _wrap_bytes_repr(object, width, allowance):
626 current = b''
627 last = len(object) // 4 * 4
628 for i in range(0, len(object), 4):
629 part = object[i: i+4]
630 candidate = current + part
631 if i == last:
632 width -= allowance
633 if len(repr(candidate)) > width:
634 if current:
635 yield repr(current)
636 current = part
637 else:
638 current = candidate
639 if current:
640 yield repr(current)
641
Fred Drake49cc01e2001-11-01 17:50:38 +0000642if __name__ == "__main__":
643 _perfcheck()