blob: 4bfcc31b25ea8e830f4675ae5aef43ad641f2bfa [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
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200345 def _format_dict_items(self, items, stream, indent, allowance, context,
346 level):
347 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200348 indent += self._indent_per_level
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200349 delimnl = ',\n' + ' ' * indent
350 last_index = len(items) - 1
351 for i, (key, ent) in enumerate(items):
352 last = i == last_index
353 rep = self._repr(key, context, level)
354 write(rep)
355 write(': ')
356 self._format(ent, stream, indent + len(rep) + 2,
357 allowance if last else 1,
358 context, level)
359 if not last:
360 write(delimnl)
361
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300362 def _format_items(self, items, stream, indent, allowance, context, level):
363 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200364 indent += self._indent_per_level
365 if self._indent_per_level > 1:
366 write((self._indent_per_level - 1) * ' ')
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300367 delimnl = ',\n' + ' ' * indent
368 delim = ''
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200369 width = max_width = self._width - indent + 1
370 it = iter(items)
371 try:
372 next_ent = next(it)
373 except StopIteration:
374 return
375 last = False
376 while not last:
377 ent = next_ent
378 try:
379 next_ent = next(it)
380 except StopIteration:
381 last = True
382 max_width -= allowance
383 width -= allowance
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300384 if self._compact:
385 rep = self._repr(ent, context, level)
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200386 w = len(rep) + 2
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300387 if width < w:
388 width = max_width
389 if delim:
390 delim = delimnl
391 if width >= w:
392 width -= w
393 write(delim)
394 delim = ', '
395 write(rep)
396 continue
397 write(delim)
398 delim = delimnl
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200399 self._format(ent, stream, indent,
400 allowance if last else 1,
401 context, level)
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300402
Fred Drakee6691ef2002-07-08 12:28:06 +0000403 def _repr(self, object, context, level):
Fred Drakeaee113d2002-04-02 05:08:35 +0000404 repr, readable, recursive = self.format(object, context.copy(),
Fred Drakee6691ef2002-07-08 12:28:06 +0000405 self._depth, level)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000406 if not readable:
Fred Drakee6691ef2002-07-08 12:28:06 +0000407 self._readable = False
Tim Petersa814db52001-05-14 07:05:58 +0000408 if recursive:
Fred Drakee6691ef2002-07-08 12:28:06 +0000409 self._recursive = True
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000410 return repr
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000411
Fred Drakeaee113d2002-04-02 05:08:35 +0000412 def format(self, object, context, maxlevels, level):
413 """Format object for a specific context, returning a string
414 and flags indicating whether the representation is 'readable'
415 and whether the object represents a recursive construct.
416 """
Rémi Lapeyre96831c72019-03-22 18:22:20 +0100417 return _safe_repr(object, context, maxlevels, level, self._sort_dicts)
Fred Drakeaee113d2002-04-02 05:08:35 +0000418
Serhiy Storchakabedbf962015-05-12 13:35:48 +0300419 def _pprint_default_dict(self, object, stream, indent, allowance, context, level):
420 if not len(object):
421 stream.write(repr(object))
422 return
423 rdf = self._repr(object.default_factory, context, level)
424 cls = object.__class__
425 indent += len(cls.__name__) + 1
426 stream.write('%s(%s,\n%s' % (cls.__name__, rdf, ' ' * indent))
427 self._pprint_dict(object, stream, indent, allowance + 1, context, level)
428 stream.write(')')
429
430 _dispatch[_collections.defaultdict.__repr__] = _pprint_default_dict
431
432 def _pprint_counter(self, object, stream, indent, allowance, context, level):
433 if not len(object):
434 stream.write(repr(object))
435 return
436 cls = object.__class__
437 stream.write(cls.__name__ + '({')
438 if self._indent_per_level > 1:
439 stream.write((self._indent_per_level - 1) * ' ')
440 items = object.most_common()
441 self._format_dict_items(items, stream,
442 indent + len(cls.__name__) + 1, allowance + 2,
443 context, level)
444 stream.write('})')
445
446 _dispatch[_collections.Counter.__repr__] = _pprint_counter
447
448 def _pprint_chain_map(self, object, stream, indent, allowance, context, level):
449 if not len(object.maps):
450 stream.write(repr(object))
451 return
452 cls = object.__class__
453 stream.write(cls.__name__ + '(')
454 indent += len(cls.__name__) + 1
455 for i, m in enumerate(object.maps):
456 if i == len(object.maps) - 1:
457 self._format(m, stream, indent, allowance + 1, context, level)
458 stream.write(')')
459 else:
460 self._format(m, stream, indent, 1, context, level)
461 stream.write(',\n' + ' ' * indent)
462
463 _dispatch[_collections.ChainMap.__repr__] = _pprint_chain_map
464
465 def _pprint_deque(self, object, stream, indent, allowance, context, level):
466 if not len(object):
467 stream.write(repr(object))
468 return
469 cls = object.__class__
470 stream.write(cls.__name__ + '(')
471 indent += len(cls.__name__) + 1
472 stream.write('[')
473 if object.maxlen is None:
474 self._format_items(object, stream, indent, allowance + 2,
475 context, level)
476 stream.write('])')
477 else:
478 self._format_items(object, stream, indent, 2,
479 context, level)
480 rml = self._repr(object.maxlen, context, level)
481 stream.write('],\n%smaxlen=%s)' % (' ' * indent, rml))
482
483 _dispatch[_collections.deque.__repr__] = _pprint_deque
484
485 def _pprint_user_dict(self, object, stream, indent, allowance, context, level):
486 self._format(object.data, stream, indent, allowance, context, level - 1)
487
488 _dispatch[_collections.UserDict.__repr__] = _pprint_user_dict
489
490 def _pprint_user_list(self, object, stream, indent, allowance, context, level):
491 self._format(object.data, stream, indent, allowance, context, level - 1)
492
493 _dispatch[_collections.UserList.__repr__] = _pprint_user_list
494
495 def _pprint_user_string(self, object, stream, indent, allowance, context, level):
496 self._format(object.data, stream, indent, allowance, context, level - 1)
497
498 _dispatch[_collections.UserString.__repr__] = _pprint_user_string
Fred Drakeaee113d2002-04-02 05:08:35 +0000499
Tim Petersa814db52001-05-14 07:05:58 +0000500# Return triple (repr_string, isreadable, isrecursive).
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000501
Rémi Lapeyre96831c72019-03-22 18:22:20 +0100502def _safe_repr(object, context, maxlevels, level, sort_dicts):
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200503 typ = type(object)
Serhiy Storchaka8eb1f072015-05-16 21:38:05 +0300504 if typ in _builtin_scalars:
505 return repr(object), True, False
Tim Peters95b3f782001-05-14 18:39:41 +0000506
Walter Dörwald1b626ca2004-11-15 13:51:41 +0000507 r = getattr(typ, "__repr__", None)
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000508 if issubclass(typ, dict) and r is dict.__repr__:
Fred Drake49cc01e2001-11-01 17:50:38 +0000509 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000510 return "{}", True, False
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200511 objid = id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000512 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000513 return "{...}", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000514 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000515 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000516 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000517 readable = True
518 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000519 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000520 append = components.append
521 level += 1
Rémi Lapeyre96831c72019-03-22 18:22:20 +0100522 if sort_dicts:
523 items = sorted(object.items(), key=_safe_tuple)
524 else:
525 items = object.items()
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000526 for k, v in items:
Rémi Lapeyre96831c72019-03-22 18:22:20 +0100527 krepr, kreadable, krecur = _safe_repr(k, context, maxlevels, level, sort_dicts)
528 vrepr, vreadable, vrecur = _safe_repr(v, context, maxlevels, level, sort_dicts)
Fred Drake49cc01e2001-11-01 17:50:38 +0000529 append("%s: %s" % (krepr, vrepr))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000530 readable = readable and kreadable and vreadable
Fred Drake49cc01e2001-11-01 17:50:38 +0000531 if krecur or vrecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000532 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000533 del context[objid]
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200534 return "{%s}" % ", ".join(components), readable, recursive
Tim Peters95b3f782001-05-14 18:39:41 +0000535
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000536 if (issubclass(typ, list) and r is list.__repr__) or \
537 (issubclass(typ, tuple) and r is tuple.__repr__):
538 if issubclass(typ, list):
Fred Drake49cc01e2001-11-01 17:50:38 +0000539 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000540 return "[]", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000541 format = "[%s]"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200542 elif len(object) == 1:
Fred Drake49cc01e2001-11-01 17:50:38 +0000543 format = "(%s,)"
544 else:
545 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000546 return "()", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000547 format = "(%s)"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200548 objid = id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000549 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000550 return format % "...", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000551 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000552 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000553 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000554 readable = True
555 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000556 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000557 append = components.append
558 level += 1
559 for o in object:
Rémi Lapeyre96831c72019-03-22 18:22:20 +0100560 orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level, sort_dicts)
Fred Drake49cc01e2001-11-01 17:50:38 +0000561 append(orepr)
562 if not oreadable:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000563 readable = False
Fred Drake49cc01e2001-11-01 17:50:38 +0000564 if orecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000565 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000566 del context[objid]
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200567 return format % ", ".join(components), readable, recursive
Tim Peters88768482001-11-13 21:51:26 +0000568
Walter Dörwald70a6b492004-02-12 17:35:32 +0000569 rep = repr(object)
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000570 return rep, (rep and not rep.startswith('<')), False
Tim Peters95b3f782001-05-14 18:39:41 +0000571
Serhiy Storchaka8eb1f072015-05-16 21:38:05 +0300572_builtin_scalars = frozenset({str, bytes, bytearray, int, float, complex,
573 bool, type(None)})
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000574
Fred Drake49cc01e2001-11-01 17:50:38 +0000575def _recursion(object):
576 return ("<Recursion on %s with id=%s>"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200577 % (type(object).__name__, id(object)))
Fred Drakea89fda01997-04-16 16:59:30 +0000578
Fred Drake49cc01e2001-11-01 17:50:38 +0000579
580def _perfcheck(object=None):
581 import time
582 if object is None:
583 object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
584 p = PrettyPrinter()
Victor Stinner8db5b542018-12-17 11:30:34 +0100585 t1 = time.perf_counter()
Rémi Lapeyre96831c72019-03-22 18:22:20 +0100586 _safe_repr(object, {}, None, 0, True)
Victor Stinner8db5b542018-12-17 11:30:34 +0100587 t2 = time.perf_counter()
Fred Drake49cc01e2001-11-01 17:50:38 +0000588 p.pformat(object)
Victor Stinner8db5b542018-12-17 11:30:34 +0100589 t3 = time.perf_counter()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000590 print("_safe_repr:", t2 - t1)
591 print("pformat:", t3 - t2)
Fred Drake49cc01e2001-11-01 17:50:38 +0000592
Serhiy Storchaka022f2032015-03-24 19:22:37 +0200593def _wrap_bytes_repr(object, width, allowance):
594 current = b''
595 last = len(object) // 4 * 4
596 for i in range(0, len(object), 4):
597 part = object[i: i+4]
598 candidate = current + part
599 if i == last:
600 width -= allowance
601 if len(repr(candidate)) > width:
602 if current:
603 yield repr(current)
604 current = part
605 else:
606 current = candidate
607 if current:
608 yield repr(current)
609
Fred Drake49cc01e2001-11-01 17:50:38 +0000610if __name__ == "__main__":
611 _perfcheck()