blob: a8af50e5a68611a0fcf56439fbd72d9f6a2529a0 [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."""
Irit Katrielff420f02020-11-23 13:31:31 +000067 return PrettyPrinter()._safe_repr(object, {}, None, 0)[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()."""
Irit Katrielff420f02020-11-23 13:31:31 +000071 return PrettyPrinter()._safe_repr(object, {}, None, 0)[1]
Tim Petersa814db52001-05-14 07:05:58 +000072
73def isrecursive(object):
74 """Determine if object requires a recursive representation."""
Irit Katrielff420f02020-11-23 13:31:31 +000075 return PrettyPrinter()._safe_repr(object, {}, None, 0)[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
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200179 stream.write(rep)
180
181 _dispatch = {}
182
183 def _pprint_dict(self, object, stream, indent, allowance, context, level):
Fred Drake49cc01e2001-11-01 17:50:38 +0000184 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200185 write('{')
186 if self._indent_per_level > 1:
187 write((self._indent_per_level - 1) * ' ')
188 length = len(object)
189 if length:
Rémi Lapeyre96831c72019-03-22 18:22:20 +0100190 if self._sort_dicts:
191 items = sorted(object.items(), key=_safe_tuple)
192 else:
193 items = object.items()
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200194 self._format_dict_items(items, stream, indent, allowance + 1,
195 context, level)
196 write('}')
Fred Drakea89fda01997-04-16 16:59:30 +0000197
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200198 _dispatch[dict.__repr__] = _pprint_dict
Serhiy Storchakaaa4c36f2015-03-26 08:51:33 +0200199
200 def _pprint_ordered_dict(self, object, stream, indent, allowance, context, level):
201 if not len(object):
202 stream.write(repr(object))
203 return
204 cls = object.__class__
205 stream.write(cls.__name__ + '(')
206 self._format(list(object.items()), stream,
207 indent + len(cls.__name__) + 1, allowance + 1,
208 context, level)
209 stream.write(')')
210
211 _dispatch[_collections.OrderedDict.__repr__] = _pprint_ordered_dict
Fred Drakea89fda01997-04-16 16:59:30 +0000212
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200213 def _pprint_list(self, object, stream, indent, allowance, context, level):
214 stream.write('[')
215 self._format_items(object, stream, indent, allowance + 1,
216 context, level)
217 stream.write(']')
Fred Drakea89fda01997-04-16 16:59:30 +0000218
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200219 _dispatch[list.__repr__] = _pprint_list
220
221 def _pprint_tuple(self, object, stream, indent, allowance, context, level):
222 stream.write('(')
223 endchar = ',)' if len(object) == 1 else ')'
224 self._format_items(object, stream, indent, allowance + len(endchar),
225 context, level)
226 stream.write(endchar)
227
228 _dispatch[tuple.__repr__] = _pprint_tuple
229
230 def _pprint_set(self, object, stream, indent, allowance, context, level):
231 if not len(object):
232 stream.write(repr(object))
233 return
234 typ = object.__class__
235 if typ is set:
236 stream.write('{')
237 endchar = '}'
238 else:
239 stream.write(typ.__name__ + '({')
240 endchar = '})'
241 indent += len(typ.__name__) + 1
242 object = sorted(object, key=_safe_key)
243 self._format_items(object, stream, indent, allowance + len(endchar),
244 context, level)
245 stream.write(endchar)
246
247 _dispatch[set.__repr__] = _pprint_set
248 _dispatch[frozenset.__repr__] = _pprint_set
249
250 def _pprint_str(self, object, stream, indent, allowance, context, level):
251 write = stream.write
252 if not len(object):
253 write(repr(object))
254 return
255 chunks = []
256 lines = object.splitlines(True)
257 if level == 1:
258 indent += 1
259 allowance += 1
260 max_width1 = max_width = self._width - indent
261 for i, line in enumerate(lines):
262 rep = repr(line)
263 if i == len(lines) - 1:
264 max_width1 -= allowance
265 if len(rep) <= max_width1:
266 chunks.append(rep)
267 else:
268 # A list of alternating (non-space, space) strings
269 parts = re.findall(r'\S*\s*', line)
270 assert parts
271 assert not parts[-1]
272 parts.pop() # drop empty last part
273 max_width2 = max_width
274 current = ''
275 for j, part in enumerate(parts):
276 candidate = current + part
277 if j == len(parts) - 1 and i == len(lines) - 1:
278 max_width2 -= allowance
279 if len(repr(candidate)) > max_width2:
Serhiy Storchakafe3dc372014-12-20 20:57:15 +0200280 if current:
281 chunks.append(repr(current))
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200282 current = part
283 else:
284 current = candidate
285 if current:
286 chunks.append(repr(current))
287 if len(chunks) == 1:
288 write(rep)
289 return
290 if level == 1:
291 write('(')
292 for i, rep in enumerate(chunks):
293 if i > 0:
294 write('\n' + ' '*indent)
295 write(rep)
296 if level == 1:
297 write(')')
298
299 _dispatch[str.__repr__] = _pprint_str
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000300
Serhiy Storchaka022f2032015-03-24 19:22:37 +0200301 def _pprint_bytes(self, object, stream, indent, allowance, context, level):
302 write = stream.write
303 if len(object) <= 4:
304 write(repr(object))
305 return
306 parens = level == 1
307 if parens:
308 indent += 1
309 allowance += 1
310 write('(')
311 delim = ''
312 for rep in _wrap_bytes_repr(object, self._width - indent, allowance):
313 write(delim)
314 write(rep)
315 if not delim:
316 delim = '\n' + ' '*indent
317 if parens:
318 write(')')
319
320 _dispatch[bytes.__repr__] = _pprint_bytes
321
322 def _pprint_bytearray(self, object, stream, indent, allowance, context, level):
323 write = stream.write
324 write('bytearray(')
325 self._pprint_bytes(bytes(object), stream, indent + 10,
326 allowance + 1, context, level + 1)
327 write(')')
328
329 _dispatch[bytearray.__repr__] = _pprint_bytearray
330
Serhiy Storchaka87eb4822015-03-24 19:31:50 +0200331 def _pprint_mappingproxy(self, object, stream, indent, allowance, context, level):
332 stream.write('mappingproxy(')
333 self._format(object.copy(), stream, indent + 13, allowance + 1,
334 context, level)
335 stream.write(')')
336
337 _dispatch[_types.MappingProxyType.__repr__] = _pprint_mappingproxy
338
Carl Bordum Hansen06a89162019-06-27 01:13:18 +0200339 def _pprint_simplenamespace(self, object, stream, indent, allowance, context, level):
340 if type(object) is _types.SimpleNamespace:
341 # The SimpleNamespace repr is "namespace" instead of the class
342 # name, so we do the same here. For subclasses; use the class name.
343 cls_name = 'namespace'
344 else:
345 cls_name = object.__class__.__name__
346 indent += len(cls_name) + 1
347 delimnl = ',\n' + ' ' * indent
348 items = object.__dict__.items()
349 last_index = len(items) - 1
350
351 stream.write(cls_name + '(')
352 for i, (key, ent) in enumerate(items):
353 stream.write(key)
354 stream.write('=')
355
356 last = i == last_index
357 self._format(ent, stream, indent + len(key) + 1,
358 allowance if last else 1,
359 context, level)
360 if not last:
361 stream.write(delimnl)
362 stream.write(')')
363
364 _dispatch[_types.SimpleNamespace.__repr__] = _pprint_simplenamespace
365
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200366 def _format_dict_items(self, items, stream, indent, allowance, context,
367 level):
368 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200369 indent += self._indent_per_level
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200370 delimnl = ',\n' + ' ' * indent
371 last_index = len(items) - 1
372 for i, (key, ent) in enumerate(items):
373 last = i == last_index
374 rep = self._repr(key, context, level)
375 write(rep)
376 write(': ')
377 self._format(ent, stream, indent + len(rep) + 2,
378 allowance if last else 1,
379 context, level)
380 if not last:
381 write(delimnl)
382
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300383 def _format_items(self, items, stream, indent, allowance, context, level):
384 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200385 indent += self._indent_per_level
386 if self._indent_per_level > 1:
387 write((self._indent_per_level - 1) * ' ')
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300388 delimnl = ',\n' + ' ' * indent
389 delim = ''
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200390 width = max_width = self._width - indent + 1
391 it = iter(items)
392 try:
393 next_ent = next(it)
394 except StopIteration:
395 return
396 last = False
397 while not last:
398 ent = next_ent
399 try:
400 next_ent = next(it)
401 except StopIteration:
402 last = True
403 max_width -= allowance
404 width -= allowance
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300405 if self._compact:
406 rep = self._repr(ent, context, level)
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200407 w = len(rep) + 2
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300408 if width < w:
409 width = max_width
410 if delim:
411 delim = delimnl
412 if width >= w:
413 width -= w
414 write(delim)
415 delim = ', '
416 write(rep)
417 continue
418 write(delim)
419 delim = delimnl
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200420 self._format(ent, stream, indent,
421 allowance if last else 1,
422 context, level)
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300423
Fred Drakee6691ef2002-07-08 12:28:06 +0000424 def _repr(self, object, context, level):
Fred Drakeaee113d2002-04-02 05:08:35 +0000425 repr, readable, recursive = self.format(object, context.copy(),
Fred Drakee6691ef2002-07-08 12:28:06 +0000426 self._depth, level)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000427 if not readable:
Fred Drakee6691ef2002-07-08 12:28:06 +0000428 self._readable = False
Tim Petersa814db52001-05-14 07:05:58 +0000429 if recursive:
Fred Drakee6691ef2002-07-08 12:28:06 +0000430 self._recursive = True
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000431 return repr
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000432
Fred Drakeaee113d2002-04-02 05:08:35 +0000433 def format(self, object, context, maxlevels, level):
434 """Format object for a specific context, returning a string
435 and flags indicating whether the representation is 'readable'
436 and whether the object represents a recursive construct.
437 """
Irit Katrielff420f02020-11-23 13:31:31 +0000438 return self._safe_repr(object, context, maxlevels, level)
Fred Drakeaee113d2002-04-02 05:08:35 +0000439
Serhiy Storchakabedbf962015-05-12 13:35:48 +0300440 def _pprint_default_dict(self, object, stream, indent, allowance, context, level):
441 if not len(object):
442 stream.write(repr(object))
443 return
444 rdf = self._repr(object.default_factory, context, level)
445 cls = object.__class__
446 indent += len(cls.__name__) + 1
447 stream.write('%s(%s,\n%s' % (cls.__name__, rdf, ' ' * indent))
448 self._pprint_dict(object, stream, indent, allowance + 1, context, level)
449 stream.write(')')
450
451 _dispatch[_collections.defaultdict.__repr__] = _pprint_default_dict
452
453 def _pprint_counter(self, object, stream, indent, allowance, context, level):
454 if not len(object):
455 stream.write(repr(object))
456 return
457 cls = object.__class__
458 stream.write(cls.__name__ + '({')
459 if self._indent_per_level > 1:
460 stream.write((self._indent_per_level - 1) * ' ')
461 items = object.most_common()
462 self._format_dict_items(items, stream,
463 indent + len(cls.__name__) + 1, allowance + 2,
464 context, level)
465 stream.write('})')
466
467 _dispatch[_collections.Counter.__repr__] = _pprint_counter
468
469 def _pprint_chain_map(self, object, stream, indent, allowance, context, level):
470 if not len(object.maps):
471 stream.write(repr(object))
472 return
473 cls = object.__class__
474 stream.write(cls.__name__ + '(')
475 indent += len(cls.__name__) + 1
476 for i, m in enumerate(object.maps):
477 if i == len(object.maps) - 1:
478 self._format(m, stream, indent, allowance + 1, context, level)
479 stream.write(')')
480 else:
481 self._format(m, stream, indent, 1, context, level)
482 stream.write(',\n' + ' ' * indent)
483
484 _dispatch[_collections.ChainMap.__repr__] = _pprint_chain_map
485
486 def _pprint_deque(self, object, stream, indent, allowance, context, level):
487 if not len(object):
488 stream.write(repr(object))
489 return
490 cls = object.__class__
491 stream.write(cls.__name__ + '(')
492 indent += len(cls.__name__) + 1
493 stream.write('[')
494 if object.maxlen is None:
495 self._format_items(object, stream, indent, allowance + 2,
496 context, level)
497 stream.write('])')
498 else:
499 self._format_items(object, stream, indent, 2,
500 context, level)
501 rml = self._repr(object.maxlen, context, level)
502 stream.write('],\n%smaxlen=%s)' % (' ' * indent, rml))
503
504 _dispatch[_collections.deque.__repr__] = _pprint_deque
505
506 def _pprint_user_dict(self, object, stream, indent, allowance, context, level):
507 self._format(object.data, stream, indent, allowance, context, level - 1)
508
509 _dispatch[_collections.UserDict.__repr__] = _pprint_user_dict
510
511 def _pprint_user_list(self, object, stream, indent, allowance, context, level):
512 self._format(object.data, stream, indent, allowance, context, level - 1)
513
514 _dispatch[_collections.UserList.__repr__] = _pprint_user_list
515
516 def _pprint_user_string(self, object, stream, indent, allowance, context, level):
517 self._format(object.data, stream, indent, allowance, context, level - 1)
518
519 _dispatch[_collections.UserString.__repr__] = _pprint_user_string
Fred Drakeaee113d2002-04-02 05:08:35 +0000520
Irit Katrielff420f02020-11-23 13:31:31 +0000521 def _safe_repr(self, object, context, maxlevels, level):
522 # Return triple (repr_string, isreadable, isrecursive).
523 typ = type(object)
524 if typ in _builtin_scalars:
525 return repr(object), True, False
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000526
Irit Katrielff420f02020-11-23 13:31:31 +0000527 r = getattr(typ, "__repr__", None)
528 if issubclass(typ, dict) and r is dict.__repr__:
Fred Drake49cc01e2001-11-01 17:50:38 +0000529 if not object:
Irit Katrielff420f02020-11-23 13:31:31 +0000530 return "{}", True, False
531 objid = id(object)
532 if maxlevels and level >= maxlevels:
533 return "{...}", False, objid in context
534 if objid in context:
535 return _recursion(object), False, True
536 context[objid] = 1
537 readable = True
538 recursive = False
539 components = []
540 append = components.append
541 level += 1
542 if self._sort_dicts:
543 items = sorted(object.items(), key=_safe_tuple)
544 else:
545 items = object.items()
546 for k, v in items:
547 krepr, kreadable, krecur = self.format(
548 k, context, maxlevels, level)
549 vrepr, vreadable, vrecur = self.format(
550 v, context, maxlevels, level)
551 append("%s: %s" % (krepr, vrepr))
552 readable = readable and kreadable and vreadable
553 if krecur or vrecur:
554 recursive = True
555 del context[objid]
556 return "{%s}" % ", ".join(components), readable, recursive
Tim Peters88768482001-11-13 21:51:26 +0000557
Irit Katrielff420f02020-11-23 13:31:31 +0000558 if (issubclass(typ, list) and r is list.__repr__) or \
559 (issubclass(typ, tuple) and r is tuple.__repr__):
560 if issubclass(typ, list):
561 if not object:
562 return "[]", True, False
563 format = "[%s]"
564 elif len(object) == 1:
565 format = "(%s,)"
566 else:
567 if not object:
568 return "()", True, False
569 format = "(%s)"
570 objid = id(object)
571 if maxlevels and level >= maxlevels:
572 return format % "...", False, objid in context
573 if objid in context:
574 return _recursion(object), False, True
575 context[objid] = 1
576 readable = True
577 recursive = False
578 components = []
579 append = components.append
580 level += 1
581 for o in object:
582 orepr, oreadable, orecur = self.format(
583 o, context, maxlevels, level)
584 append(orepr)
585 if not oreadable:
586 readable = False
587 if orecur:
588 recursive = True
589 del context[objid]
590 return format % ", ".join(components), readable, recursive
591
592 rep = repr(object)
593 return rep, (rep and not rep.startswith('<')), False
Tim Peters95b3f782001-05-14 18:39:41 +0000594
Serhiy Storchaka8eb1f072015-05-16 21:38:05 +0300595_builtin_scalars = frozenset({str, bytes, bytearray, int, float, complex,
596 bool, type(None)})
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000597
Fred Drake49cc01e2001-11-01 17:50:38 +0000598def _recursion(object):
599 return ("<Recursion on %s with id=%s>"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200600 % (type(object).__name__, id(object)))
Fred Drakea89fda01997-04-16 16:59:30 +0000601
Fred Drake49cc01e2001-11-01 17:50:38 +0000602
603def _perfcheck(object=None):
604 import time
605 if object is None:
606 object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
607 p = PrettyPrinter()
Victor Stinner8db5b542018-12-17 11:30:34 +0100608 t1 = time.perf_counter()
Irit Katrielff420f02020-11-23 13:31:31 +0000609 p._safe_repr(object, {}, None, 0, True)
Victor Stinner8db5b542018-12-17 11:30:34 +0100610 t2 = time.perf_counter()
Fred Drake49cc01e2001-11-01 17:50:38 +0000611 p.pformat(object)
Victor Stinner8db5b542018-12-17 11:30:34 +0100612 t3 = time.perf_counter()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000613 print("_safe_repr:", t2 - t1)
614 print("pformat:", t3 - t2)
Fred Drake49cc01e2001-11-01 17:50:38 +0000615
Serhiy Storchaka022f2032015-03-24 19:22:37 +0200616def _wrap_bytes_repr(object, width, allowance):
617 current = b''
618 last = len(object) // 4 * 4
619 for i in range(0, len(object), 4):
620 part = object[i: i+4]
621 candidate = current + part
622 if i == last:
623 width -= allowance
624 if len(repr(candidate)) > width:
625 if current:
626 yield repr(current)
627 current = part
628 else:
629 current = candidate
630 if current:
631 yield repr(current)
632
Fred Drake49cc01e2001-11-01 17:50:38 +0000633if __name__ == "__main__":
634 _perfcheck()