blob: 7c1118a484b268fee26760fc0ca1ec76a533f52a [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, *,
Rémi Lapeyre96831c72019-03-22 18:22:20 +010048 compact=False, sort_dicts=True):
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,
Rémi Lapeyre96831c72019-03-22 18:22:20 +010052 compact=compact, sort_dicts=sort_dicts)
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, *,
56 compact=False, sort_dicts=True):
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,
Rémi Lapeyre96831c72019-03-22 18:22:20 +010059 compact=compact, sort_dicts=sort_dicts).pformat(object)
60
61def pp(object, *args, sort_dicts=False, **kwargs):
62 """Pretty-print a Python object"""
63 pprint(object, *args, sort_dicts=sort_dicts, **kwargs)
Guido van Rossum5e92aff1997-04-16 00:49:59 +000064
Fred Drakea89fda01997-04-16 16:59:30 +000065def saferepr(object):
66 """Version of repr() which can handle recursive data structures."""
Rémi Lapeyre96831c72019-03-22 18:22:20 +010067 return _safe_repr(object, {}, None, 0, True)[0]
Guido van Rossum5e92aff1997-04-16 00:49:59 +000068
Tim Petersa814db52001-05-14 07:05:58 +000069def isreadable(object):
70 """Determine if saferepr(object) is readable by eval()."""
Rémi Lapeyre96831c72019-03-22 18:22:20 +010071 return _safe_repr(object, {}, None, 0, True)[1]
Tim Petersa814db52001-05-14 07:05:58 +000072
73def isrecursive(object):
74 """Determine if object requires a recursive representation."""
Rémi Lapeyre96831c72019-03-22 18:22:20 +010075 return _safe_repr(object, {}, None, 0, True)[2]
Guido van Rossum5e92aff1997-04-16 00:49:59 +000076
Raymond Hettingera7da1662009-11-19 01:07:05 +000077class _safe_key:
78 """Helper function for key functions when sorting unorderable objects.
79
Serhiy Storchaka6a7b3a72016-04-17 08:32:47 +030080 The wrapped-object will fallback to a Py2.x style comparison for
Raymond Hettingera7da1662009-11-19 01:07:05 +000081 unorderable types (sorting first comparing the type name and then by
82 the obj ids). Does not work recursively, so dict.items() must have
83 _safe_key applied to both the key and the value.
84
85 """
86
87 __slots__ = ['obj']
88
89 def __init__(self, obj):
90 self.obj = obj
91
92 def __lt__(self, other):
Florent Xiclunad6da90f2012-07-21 11:17:38 +020093 try:
Serhiy Storchaka62aa7dc2015-04-06 22:52:44 +030094 return self.obj < other.obj
Florent Xiclunad6da90f2012-07-21 11:17:38 +020095 except TypeError:
Serhiy Storchaka62aa7dc2015-04-06 22:52:44 +030096 return ((str(type(self.obj)), id(self.obj)) < \
97 (str(type(other.obj)), id(other.obj)))
Raymond Hettingera7da1662009-11-19 01:07:05 +000098
99def _safe_tuple(t):
100 "Helper function for comparing 2-tuples"
101 return _safe_key(t[0]), _safe_key(t[1])
102
Fred Drakea89fda01997-04-16 16:59:30 +0000103class PrettyPrinter:
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300104 def __init__(self, indent=1, width=80, depth=None, stream=None, *,
Rémi Lapeyre96831c72019-03-22 18:22:20 +0100105 compact=False, sort_dicts=True):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000106 """Handle pretty printing operations onto a stream using a set of
107 configured parameters.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000108
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000109 indent
110 Number of spaces to indent for each level of nesting.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000111
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000112 width
113 Attempted maximum number of columns in the output.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000114
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000115 depth
116 The maximum depth to print out nested structures.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000117
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000118 stream
119 The desired output stream. If omitted (or false), the standard
120 output stream available at construction will be used.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000121
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300122 compact
123 If true, several items will be combined in one line.
124
Rémi Lapeyre96831c72019-03-22 18:22:20 +0100125 sort_dicts
126 If true, dict keys are sorted.
127
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000128 """
129 indent = int(indent)
130 width = int(width)
Serhiy Storchakaf3fa3082015-03-26 08:43:21 +0200131 if indent < 0:
132 raise ValueError('indent must be >= 0')
133 if depth is not None and depth <= 0:
134 raise ValueError('depth must be > 0')
135 if not width:
136 raise ValueError('width must be != 0')
Fred Drakee6691ef2002-07-08 12:28:06 +0000137 self._depth = depth
138 self._indent_per_level = indent
139 self._width = width
Raymond Hettinger16e3c422002-06-01 16:07:16 +0000140 if stream is not None:
Fred Drakee6691ef2002-07-08 12:28:06 +0000141 self._stream = stream
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000142 else:
Fred Drake397b6152002-12-31 07:14:18 +0000143 self._stream = _sys.stdout
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300144 self._compact = bool(compact)
Rémi Lapeyre96831c72019-03-22 18:22:20 +0100145 self._sort_dicts = sort_dicts
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000146
Fred Drakea89fda01997-04-16 16:59:30 +0000147 def pprint(self, object):
Walter Dörwalde62e9362005-11-11 18:18:51 +0000148 self._format(object, self._stream, 0, 0, {}, 0)
149 self._stream.write("\n")
Fred Drakea89fda01997-04-16 16:59:30 +0000150
151 def pformat(self, object):
Fred Drake397b6152002-12-31 07:14:18 +0000152 sio = _StringIO()
Fred Drakee6691ef2002-07-08 12:28:06 +0000153 self._format(object, sio, 0, 0, {}, 0)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000154 return sio.getvalue()
Fred Drakea89fda01997-04-16 16:59:30 +0000155
Fred Drakee0ffabe1997-07-18 20:42:39 +0000156 def isrecursive(self, object):
Fred Drake397b6152002-12-31 07:14:18 +0000157 return self.format(object, {}, 0, 0)[2]
Fred Drakee0ffabe1997-07-18 20:42:39 +0000158
159 def isreadable(self, object):
Fred Drake397b6152002-12-31 07:14:18 +0000160 s, readable, recursive = self.format(object, {}, 0, 0)
Fred Drakeaee113d2002-04-02 05:08:35 +0000161 return readable and not recursive
Fred Drakee0ffabe1997-07-18 20:42:39 +0000162
Fred Drakee6691ef2002-07-08 12:28:06 +0000163 def _format(self, object, stream, indent, allowance, context, level):
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200164 objid = id(object)
Fred Drake49cc01e2001-11-01 17:50:38 +0000165 if objid in context:
166 stream.write(_recursion(object))
Fred Drakee6691ef2002-07-08 12:28:06 +0000167 self._recursive = True
168 self._readable = False
Fred Drake49cc01e2001-11-01 17:50:38 +0000169 return
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200170 rep = self._repr(object, context, level)
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200171 max_width = self._width - indent - allowance
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200172 if len(rep) > max_width:
173 p = self._dispatch.get(type(object).__repr__, None)
174 if p is not None:
175 context[objid] = 1
176 p(self, object, stream, indent, allowance, context, level + 1)
177 del context[objid]
178 return
179 elif isinstance(object, dict):
180 context[objid] = 1
181 self._pprint_dict(object, stream, indent, allowance,
182 context, level + 1)
183 del context[objid]
184 return
185 stream.write(rep)
186
187 _dispatch = {}
188
189 def _pprint_dict(self, object, stream, indent, allowance, context, level):
Fred Drake49cc01e2001-11-01 17:50:38 +0000190 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200191 write('{')
192 if self._indent_per_level > 1:
193 write((self._indent_per_level - 1) * ' ')
194 length = len(object)
195 if length:
Rémi Lapeyre96831c72019-03-22 18:22:20 +0100196 if self._sort_dicts:
197 items = sorted(object.items(), key=_safe_tuple)
198 else:
199 items = object.items()
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200200 self._format_dict_items(items, stream, indent, allowance + 1,
201 context, level)
202 write('}')
Fred Drakea89fda01997-04-16 16:59:30 +0000203
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200204 _dispatch[dict.__repr__] = _pprint_dict
Serhiy Storchakaaa4c36f2015-03-26 08:51:33 +0200205
206 def _pprint_ordered_dict(self, object, stream, indent, allowance, context, level):
207 if not len(object):
208 stream.write(repr(object))
209 return
210 cls = object.__class__
211 stream.write(cls.__name__ + '(')
212 self._format(list(object.items()), stream,
213 indent + len(cls.__name__) + 1, allowance + 1,
214 context, level)
215 stream.write(')')
216
217 _dispatch[_collections.OrderedDict.__repr__] = _pprint_ordered_dict
Fred Drakea89fda01997-04-16 16:59:30 +0000218
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200219 def _pprint_list(self, object, stream, indent, allowance, context, level):
220 stream.write('[')
221 self._format_items(object, stream, indent, allowance + 1,
222 context, level)
223 stream.write(']')
Fred Drakea89fda01997-04-16 16:59:30 +0000224
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200225 _dispatch[list.__repr__] = _pprint_list
226
227 def _pprint_tuple(self, object, stream, indent, allowance, context, level):
228 stream.write('(')
229 endchar = ',)' if len(object) == 1 else ')'
230 self._format_items(object, stream, indent, allowance + len(endchar),
231 context, level)
232 stream.write(endchar)
233
234 _dispatch[tuple.__repr__] = _pprint_tuple
235
236 def _pprint_set(self, object, stream, indent, allowance, context, level):
237 if not len(object):
238 stream.write(repr(object))
239 return
240 typ = object.__class__
241 if typ is set:
242 stream.write('{')
243 endchar = '}'
244 else:
245 stream.write(typ.__name__ + '({')
246 endchar = '})'
247 indent += len(typ.__name__) + 1
248 object = sorted(object, key=_safe_key)
249 self._format_items(object, stream, indent, allowance + len(endchar),
250 context, level)
251 stream.write(endchar)
252
253 _dispatch[set.__repr__] = _pprint_set
254 _dispatch[frozenset.__repr__] = _pprint_set
255
256 def _pprint_str(self, object, stream, indent, allowance, context, level):
257 write = stream.write
258 if not len(object):
259 write(repr(object))
260 return
261 chunks = []
262 lines = object.splitlines(True)
263 if level == 1:
264 indent += 1
265 allowance += 1
266 max_width1 = max_width = self._width - indent
267 for i, line in enumerate(lines):
268 rep = repr(line)
269 if i == len(lines) - 1:
270 max_width1 -= allowance
271 if len(rep) <= max_width1:
272 chunks.append(rep)
273 else:
274 # A list of alternating (non-space, space) strings
275 parts = re.findall(r'\S*\s*', line)
276 assert parts
277 assert not parts[-1]
278 parts.pop() # drop empty last part
279 max_width2 = max_width
280 current = ''
281 for j, part in enumerate(parts):
282 candidate = current + part
283 if j == len(parts) - 1 and i == len(lines) - 1:
284 max_width2 -= allowance
285 if len(repr(candidate)) > max_width2:
Serhiy Storchakafe3dc372014-12-20 20:57:15 +0200286 if current:
287 chunks.append(repr(current))
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200288 current = part
289 else:
290 current = candidate
291 if current:
292 chunks.append(repr(current))
293 if len(chunks) == 1:
294 write(rep)
295 return
296 if level == 1:
297 write('(')
298 for i, rep in enumerate(chunks):
299 if i > 0:
300 write('\n' + ' '*indent)
301 write(rep)
302 if level == 1:
303 write(')')
304
305 _dispatch[str.__repr__] = _pprint_str
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000306
Serhiy Storchaka022f2032015-03-24 19:22:37 +0200307 def _pprint_bytes(self, object, stream, indent, allowance, context, level):
308 write = stream.write
309 if len(object) <= 4:
310 write(repr(object))
311 return
312 parens = level == 1
313 if parens:
314 indent += 1
315 allowance += 1
316 write('(')
317 delim = ''
318 for rep in _wrap_bytes_repr(object, self._width - indent, allowance):
319 write(delim)
320 write(rep)
321 if not delim:
322 delim = '\n' + ' '*indent
323 if parens:
324 write(')')
325
326 _dispatch[bytes.__repr__] = _pprint_bytes
327
328 def _pprint_bytearray(self, object, stream, indent, allowance, context, level):
329 write = stream.write
330 write('bytearray(')
331 self._pprint_bytes(bytes(object), stream, indent + 10,
332 allowance + 1, context, level + 1)
333 write(')')
334
335 _dispatch[bytearray.__repr__] = _pprint_bytearray
336
Serhiy Storchaka87eb4822015-03-24 19:31:50 +0200337 def _pprint_mappingproxy(self, object, stream, indent, allowance, context, level):
338 stream.write('mappingproxy(')
339 self._format(object.copy(), stream, indent + 13, allowance + 1,
340 context, level)
341 stream.write(')')
342
343 _dispatch[_types.MappingProxyType.__repr__] = _pprint_mappingproxy
344
Carl Bordum Hansen06a89162019-06-27 01:13:18 +0200345 def _pprint_simplenamespace(self, object, stream, indent, allowance, context, level):
346 if type(object) is _types.SimpleNamespace:
347 # The SimpleNamespace repr is "namespace" instead of the class
348 # name, so we do the same here. For subclasses; use the class name.
349 cls_name = 'namespace'
350 else:
351 cls_name = object.__class__.__name__
352 indent += len(cls_name) + 1
353 delimnl = ',\n' + ' ' * indent
354 items = object.__dict__.items()
355 last_index = len(items) - 1
356
357 stream.write(cls_name + '(')
358 for i, (key, ent) in enumerate(items):
359 stream.write(key)
360 stream.write('=')
361
362 last = i == last_index
363 self._format(ent, stream, indent + len(key) + 1,
364 allowance if last else 1,
365 context, level)
366 if not last:
367 stream.write(delimnl)
368 stream.write(')')
369
370 _dispatch[_types.SimpleNamespace.__repr__] = _pprint_simplenamespace
371
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200372 def _format_dict_items(self, items, stream, indent, allowance, context,
373 level):
374 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200375 indent += self._indent_per_level
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200376 delimnl = ',\n' + ' ' * indent
377 last_index = len(items) - 1
378 for i, (key, ent) in enumerate(items):
379 last = i == last_index
380 rep = self._repr(key, context, level)
381 write(rep)
382 write(': ')
383 self._format(ent, stream, indent + len(rep) + 2,
384 allowance if last else 1,
385 context, level)
386 if not last:
387 write(delimnl)
388
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300389 def _format_items(self, items, stream, indent, allowance, context, level):
390 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200391 indent += self._indent_per_level
392 if self._indent_per_level > 1:
393 write((self._indent_per_level - 1) * ' ')
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300394 delimnl = ',\n' + ' ' * indent
395 delim = ''
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200396 width = max_width = self._width - indent + 1
397 it = iter(items)
398 try:
399 next_ent = next(it)
400 except StopIteration:
401 return
402 last = False
403 while not last:
404 ent = next_ent
405 try:
406 next_ent = next(it)
407 except StopIteration:
408 last = True
409 max_width -= allowance
410 width -= allowance
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300411 if self._compact:
412 rep = self._repr(ent, context, level)
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200413 w = len(rep) + 2
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300414 if width < w:
415 width = max_width
416 if delim:
417 delim = delimnl
418 if width >= w:
419 width -= w
420 write(delim)
421 delim = ', '
422 write(rep)
423 continue
424 write(delim)
425 delim = delimnl
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200426 self._format(ent, stream, indent,
427 allowance if last else 1,
428 context, level)
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300429
Fred Drakee6691ef2002-07-08 12:28:06 +0000430 def _repr(self, object, context, level):
Fred Drakeaee113d2002-04-02 05:08:35 +0000431 repr, readable, recursive = self.format(object, context.copy(),
Fred Drakee6691ef2002-07-08 12:28:06 +0000432 self._depth, level)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000433 if not readable:
Fred Drakee6691ef2002-07-08 12:28:06 +0000434 self._readable = False
Tim Petersa814db52001-05-14 07:05:58 +0000435 if recursive:
Fred Drakee6691ef2002-07-08 12:28:06 +0000436 self._recursive = True
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000437 return repr
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000438
Fred Drakeaee113d2002-04-02 05:08:35 +0000439 def format(self, object, context, maxlevels, level):
440 """Format object for a specific context, returning a string
441 and flags indicating whether the representation is 'readable'
442 and whether the object represents a recursive construct.
443 """
Rémi Lapeyre96831c72019-03-22 18:22:20 +0100444 return _safe_repr(object, context, maxlevels, level, self._sort_dicts)
Fred Drakeaee113d2002-04-02 05:08:35 +0000445
Serhiy Storchakabedbf962015-05-12 13:35:48 +0300446 def _pprint_default_dict(self, object, stream, indent, allowance, context, level):
447 if not len(object):
448 stream.write(repr(object))
449 return
450 rdf = self._repr(object.default_factory, context, level)
451 cls = object.__class__
452 indent += len(cls.__name__) + 1
453 stream.write('%s(%s,\n%s' % (cls.__name__, rdf, ' ' * indent))
454 self._pprint_dict(object, stream, indent, allowance + 1, context, level)
455 stream.write(')')
456
457 _dispatch[_collections.defaultdict.__repr__] = _pprint_default_dict
458
459 def _pprint_counter(self, object, stream, indent, allowance, context, level):
460 if not len(object):
461 stream.write(repr(object))
462 return
463 cls = object.__class__
464 stream.write(cls.__name__ + '({')
465 if self._indent_per_level > 1:
466 stream.write((self._indent_per_level - 1) * ' ')
467 items = object.most_common()
468 self._format_dict_items(items, stream,
469 indent + len(cls.__name__) + 1, allowance + 2,
470 context, level)
471 stream.write('})')
472
473 _dispatch[_collections.Counter.__repr__] = _pprint_counter
474
475 def _pprint_chain_map(self, object, stream, indent, allowance, context, level):
476 if not len(object.maps):
477 stream.write(repr(object))
478 return
479 cls = object.__class__
480 stream.write(cls.__name__ + '(')
481 indent += len(cls.__name__) + 1
482 for i, m in enumerate(object.maps):
483 if i == len(object.maps) - 1:
484 self._format(m, stream, indent, allowance + 1, context, level)
485 stream.write(')')
486 else:
487 self._format(m, stream, indent, 1, context, level)
488 stream.write(',\n' + ' ' * indent)
489
490 _dispatch[_collections.ChainMap.__repr__] = _pprint_chain_map
491
492 def _pprint_deque(self, object, stream, indent, allowance, context, level):
493 if not len(object):
494 stream.write(repr(object))
495 return
496 cls = object.__class__
497 stream.write(cls.__name__ + '(')
498 indent += len(cls.__name__) + 1
499 stream.write('[')
500 if object.maxlen is None:
501 self._format_items(object, stream, indent, allowance + 2,
502 context, level)
503 stream.write('])')
504 else:
505 self._format_items(object, stream, indent, 2,
506 context, level)
507 rml = self._repr(object.maxlen, context, level)
508 stream.write('],\n%smaxlen=%s)' % (' ' * indent, rml))
509
510 _dispatch[_collections.deque.__repr__] = _pprint_deque
511
512 def _pprint_user_dict(self, object, stream, indent, allowance, context, level):
513 self._format(object.data, stream, indent, allowance, context, level - 1)
514
515 _dispatch[_collections.UserDict.__repr__] = _pprint_user_dict
516
517 def _pprint_user_list(self, object, stream, indent, allowance, context, level):
518 self._format(object.data, stream, indent, allowance, context, level - 1)
519
520 _dispatch[_collections.UserList.__repr__] = _pprint_user_list
521
522 def _pprint_user_string(self, object, stream, indent, allowance, context, level):
523 self._format(object.data, stream, indent, allowance, context, level - 1)
524
525 _dispatch[_collections.UserString.__repr__] = _pprint_user_string
Fred Drakeaee113d2002-04-02 05:08:35 +0000526
Tim Petersa814db52001-05-14 07:05:58 +0000527# Return triple (repr_string, isreadable, isrecursive).
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000528
Rémi Lapeyre96831c72019-03-22 18:22:20 +0100529def _safe_repr(object, context, maxlevels, level, sort_dicts):
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200530 typ = type(object)
Serhiy Storchaka8eb1f072015-05-16 21:38:05 +0300531 if typ in _builtin_scalars:
532 return repr(object), True, False
Tim Peters95b3f782001-05-14 18:39:41 +0000533
Walter Dörwald1b626ca2004-11-15 13:51:41 +0000534 r = getattr(typ, "__repr__", None)
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000535 if issubclass(typ, dict) and r is dict.__repr__:
Fred Drake49cc01e2001-11-01 17:50:38 +0000536 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000537 return "{}", True, False
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200538 objid = id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000539 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000540 return "{...}", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000541 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000542 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000543 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000544 readable = True
545 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000546 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000547 append = components.append
548 level += 1
Rémi Lapeyre96831c72019-03-22 18:22:20 +0100549 if sort_dicts:
550 items = sorted(object.items(), key=_safe_tuple)
551 else:
552 items = object.items()
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000553 for k, v in items:
Rémi Lapeyre96831c72019-03-22 18:22:20 +0100554 krepr, kreadable, krecur = _safe_repr(k, context, maxlevels, level, sort_dicts)
555 vrepr, vreadable, vrecur = _safe_repr(v, context, maxlevels, level, sort_dicts)
Fred Drake49cc01e2001-11-01 17:50:38 +0000556 append("%s: %s" % (krepr, vrepr))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000557 readable = readable and kreadable and vreadable
Fred Drake49cc01e2001-11-01 17:50:38 +0000558 if krecur or vrecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000559 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000560 del context[objid]
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200561 return "{%s}" % ", ".join(components), readable, recursive
Tim Peters95b3f782001-05-14 18:39:41 +0000562
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000563 if (issubclass(typ, list) and r is list.__repr__) or \
564 (issubclass(typ, tuple) and r is tuple.__repr__):
565 if issubclass(typ, list):
Fred Drake49cc01e2001-11-01 17:50:38 +0000566 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000567 return "[]", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000568 format = "[%s]"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200569 elif len(object) == 1:
Fred Drake49cc01e2001-11-01 17:50:38 +0000570 format = "(%s,)"
571 else:
572 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000573 return "()", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000574 format = "(%s)"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200575 objid = id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000576 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000577 return format % "...", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000578 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000579 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000580 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000581 readable = True
582 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000583 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000584 append = components.append
585 level += 1
586 for o in object:
Rémi Lapeyre96831c72019-03-22 18:22:20 +0100587 orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level, sort_dicts)
Fred Drake49cc01e2001-11-01 17:50:38 +0000588 append(orepr)
589 if not oreadable:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000590 readable = False
Fred Drake49cc01e2001-11-01 17:50:38 +0000591 if orecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000592 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000593 del context[objid]
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200594 return format % ", ".join(components), readable, recursive
Tim Peters88768482001-11-13 21:51:26 +0000595
Walter Dörwald70a6b492004-02-12 17:35:32 +0000596 rep = repr(object)
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000597 return rep, (rep and not rep.startswith('<')), False
Tim Peters95b3f782001-05-14 18:39:41 +0000598
Serhiy Storchaka8eb1f072015-05-16 21:38:05 +0300599_builtin_scalars = frozenset({str, bytes, bytearray, int, float, complex,
600 bool, type(None)})
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000601
Fred Drake49cc01e2001-11-01 17:50:38 +0000602def _recursion(object):
603 return ("<Recursion on %s with id=%s>"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200604 % (type(object).__name__, id(object)))
Fred Drakea89fda01997-04-16 16:59:30 +0000605
Fred Drake49cc01e2001-11-01 17:50:38 +0000606
607def _perfcheck(object=None):
608 import time
609 if object is None:
610 object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
611 p = PrettyPrinter()
Victor Stinner8db5b542018-12-17 11:30:34 +0100612 t1 = time.perf_counter()
Rémi Lapeyre96831c72019-03-22 18:22:20 +0100613 _safe_repr(object, {}, None, 0, True)
Victor Stinner8db5b542018-12-17 11:30:34 +0100614 t2 = time.perf_counter()
Fred Drake49cc01e2001-11-01 17:50:38 +0000615 p.pformat(object)
Victor Stinner8db5b542018-12-17 11:30:34 +0100616 t3 = time.perf_counter()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000617 print("_safe_repr:", t2 - t1)
618 print("pformat:", t3 - t2)
Fred Drake49cc01e2001-11-01 17:50:38 +0000619
Serhiy Storchaka022f2032015-03-24 19:22:37 +0200620def _wrap_bytes_repr(object, width, allowance):
621 current = b''
622 last = len(object) // 4 * 4
623 for i in range(0, len(object), 4):
624 part = object[i: i+4]
625 candidate = current + part
626 if i == last:
627 width -= allowance
628 if len(repr(candidate)) > width:
629 if current:
630 yield repr(current)
631 current = part
632 else:
633 current = candidate
634 if current:
635 yield repr(current)
636
Fred Drake49cc01e2001-11-01 17:50:38 +0000637if __name__ == "__main__":
638 _perfcheck()