blob: 87649b48cdfab47f93203d7864d11e70a8a11364 [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",
44 "PrettyPrinter"]
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, *,
48 compact=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,
52 compact=compact)
Fred Drakea89fda01997-04-16 16:59:30 +000053 printer.pprint(object)
Guido van Rossum5e92aff1997-04-16 00:49:59 +000054
Serhiy Storchaka7c411a42013-10-02 11:56:18 +030055def pformat(object, indent=1, width=80, depth=None, *, compact=False):
Fred Drakea89fda01997-04-16 16:59:30 +000056 """Format a Python object into a pretty-printed representation."""
Serhiy Storchaka7c411a42013-10-02 11:56:18 +030057 return PrettyPrinter(indent=indent, width=width, depth=depth,
58 compact=compact).pformat(object)
Guido van Rossum5e92aff1997-04-16 00:49:59 +000059
Fred Drakea89fda01997-04-16 16:59:30 +000060def saferepr(object):
61 """Version of repr() which can handle recursive data structures."""
Fred Drake49cc01e2001-11-01 17:50:38 +000062 return _safe_repr(object, {}, None, 0)[0]
Guido van Rossum5e92aff1997-04-16 00:49:59 +000063
Tim Petersa814db52001-05-14 07:05:58 +000064def isreadable(object):
65 """Determine if saferepr(object) is readable by eval()."""
Fred Drake49cc01e2001-11-01 17:50:38 +000066 return _safe_repr(object, {}, None, 0)[1]
Tim Petersa814db52001-05-14 07:05:58 +000067
68def isrecursive(object):
69 """Determine if object requires a recursive representation."""
Fred Drake49cc01e2001-11-01 17:50:38 +000070 return _safe_repr(object, {}, None, 0)[2]
Guido van Rossum5e92aff1997-04-16 00:49:59 +000071
Raymond Hettingera7da1662009-11-19 01:07:05 +000072class _safe_key:
73 """Helper function for key functions when sorting unorderable objects.
74
75 The wrapped-object will fallback to an Py2.x style comparison for
76 unorderable types (sorting first comparing the type name and then by
77 the obj ids). Does not work recursively, so dict.items() must have
78 _safe_key applied to both the key and the value.
79
80 """
81
82 __slots__ = ['obj']
83
84 def __init__(self, obj):
85 self.obj = obj
86
87 def __lt__(self, other):
Florent Xiclunad6da90f2012-07-21 11:17:38 +020088 try:
Serhiy Storchaka62aa7dc2015-04-06 22:52:44 +030089 return self.obj < other.obj
Florent Xiclunad6da90f2012-07-21 11:17:38 +020090 except TypeError:
Serhiy Storchaka62aa7dc2015-04-06 22:52:44 +030091 return ((str(type(self.obj)), id(self.obj)) < \
92 (str(type(other.obj)), id(other.obj)))
Raymond Hettingera7da1662009-11-19 01:07:05 +000093
94def _safe_tuple(t):
95 "Helper function for comparing 2-tuples"
96 return _safe_key(t[0]), _safe_key(t[1])
97
Fred Drakea89fda01997-04-16 16:59:30 +000098class PrettyPrinter:
Serhiy Storchaka7c411a42013-10-02 11:56:18 +030099 def __init__(self, indent=1, width=80, depth=None, stream=None, *,
100 compact=False):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000101 """Handle pretty printing operations onto a stream using a set of
102 configured parameters.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000103
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000104 indent
105 Number of spaces to indent for each level of nesting.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000106
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000107 width
108 Attempted maximum number of columns in the output.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000109
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000110 depth
111 The maximum depth to print out nested structures.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000112
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000113 stream
114 The desired output stream. If omitted (or false), the standard
115 output stream available at construction will be used.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000116
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300117 compact
118 If true, several items will be combined in one line.
119
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000120 """
121 indent = int(indent)
122 width = int(width)
Serhiy Storchakaf3fa3082015-03-26 08:43:21 +0200123 if indent < 0:
124 raise ValueError('indent must be >= 0')
125 if depth is not None and depth <= 0:
126 raise ValueError('depth must be > 0')
127 if not width:
128 raise ValueError('width must be != 0')
Fred Drakee6691ef2002-07-08 12:28:06 +0000129 self._depth = depth
130 self._indent_per_level = indent
131 self._width = width
Raymond Hettinger16e3c422002-06-01 16:07:16 +0000132 if stream is not None:
Fred Drakee6691ef2002-07-08 12:28:06 +0000133 self._stream = stream
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000134 else:
Fred Drake397b6152002-12-31 07:14:18 +0000135 self._stream = _sys.stdout
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300136 self._compact = bool(compact)
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000137
Fred Drakea89fda01997-04-16 16:59:30 +0000138 def pprint(self, object):
Walter Dörwalde62e9362005-11-11 18:18:51 +0000139 self._format(object, self._stream, 0, 0, {}, 0)
140 self._stream.write("\n")
Fred Drakea89fda01997-04-16 16:59:30 +0000141
142 def pformat(self, object):
Fred Drake397b6152002-12-31 07:14:18 +0000143 sio = _StringIO()
Fred Drakee6691ef2002-07-08 12:28:06 +0000144 self._format(object, sio, 0, 0, {}, 0)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000145 return sio.getvalue()
Fred Drakea89fda01997-04-16 16:59:30 +0000146
Fred Drakee0ffabe1997-07-18 20:42:39 +0000147 def isrecursive(self, object):
Fred Drake397b6152002-12-31 07:14:18 +0000148 return self.format(object, {}, 0, 0)[2]
Fred Drakee0ffabe1997-07-18 20:42:39 +0000149
150 def isreadable(self, object):
Fred Drake397b6152002-12-31 07:14:18 +0000151 s, readable, recursive = self.format(object, {}, 0, 0)
Fred Drakeaee113d2002-04-02 05:08:35 +0000152 return readable and not recursive
Fred Drakee0ffabe1997-07-18 20:42:39 +0000153
Fred Drakee6691ef2002-07-08 12:28:06 +0000154 def _format(self, object, stream, indent, allowance, context, level):
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200155 objid = id(object)
Fred Drake49cc01e2001-11-01 17:50:38 +0000156 if objid in context:
157 stream.write(_recursion(object))
Fred Drakee6691ef2002-07-08 12:28:06 +0000158 self._recursive = True
159 self._readable = False
Fred Drake49cc01e2001-11-01 17:50:38 +0000160 return
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200161 rep = self._repr(object, context, level)
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200162 max_width = self._width - indent - allowance
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200163 if len(rep) > max_width:
164 p = self._dispatch.get(type(object).__repr__, None)
165 if p is not None:
166 context[objid] = 1
167 p(self, object, stream, indent, allowance, context, level + 1)
168 del context[objid]
169 return
170 elif isinstance(object, dict):
171 context[objid] = 1
172 self._pprint_dict(object, stream, indent, allowance,
173 context, level + 1)
174 del context[objid]
175 return
176 stream.write(rep)
177
178 _dispatch = {}
179
180 def _pprint_dict(self, object, stream, indent, allowance, context, level):
Fred Drake49cc01e2001-11-01 17:50:38 +0000181 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200182 write('{')
183 if self._indent_per_level > 1:
184 write((self._indent_per_level - 1) * ' ')
185 length = len(object)
186 if length:
Serhiy Storchakaaa4c36f2015-03-26 08:51:33 +0200187 items = sorted(object.items(), key=_safe_tuple)
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200188 self._format_dict_items(items, stream, indent, allowance + 1,
189 context, level)
190 write('}')
Fred Drakea89fda01997-04-16 16:59:30 +0000191
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200192 _dispatch[dict.__repr__] = _pprint_dict
Serhiy Storchakaaa4c36f2015-03-26 08:51:33 +0200193
194 def _pprint_ordered_dict(self, object, stream, indent, allowance, context, level):
195 if not len(object):
196 stream.write(repr(object))
197 return
198 cls = object.__class__
199 stream.write(cls.__name__ + '(')
200 self._format(list(object.items()), stream,
201 indent + len(cls.__name__) + 1, allowance + 1,
202 context, level)
203 stream.write(')')
204
205 _dispatch[_collections.OrderedDict.__repr__] = _pprint_ordered_dict
Fred Drakea89fda01997-04-16 16:59:30 +0000206
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200207 def _pprint_list(self, object, stream, indent, allowance, context, level):
208 stream.write('[')
209 self._format_items(object, stream, indent, allowance + 1,
210 context, level)
211 stream.write(']')
Fred Drakea89fda01997-04-16 16:59:30 +0000212
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200213 _dispatch[list.__repr__] = _pprint_list
214
215 def _pprint_tuple(self, object, stream, indent, allowance, context, level):
216 stream.write('(')
217 endchar = ',)' if len(object) == 1 else ')'
218 self._format_items(object, stream, indent, allowance + len(endchar),
219 context, level)
220 stream.write(endchar)
221
222 _dispatch[tuple.__repr__] = _pprint_tuple
223
224 def _pprint_set(self, object, stream, indent, allowance, context, level):
225 if not len(object):
226 stream.write(repr(object))
227 return
228 typ = object.__class__
229 if typ is set:
230 stream.write('{')
231 endchar = '}'
232 else:
233 stream.write(typ.__name__ + '({')
234 endchar = '})'
235 indent += len(typ.__name__) + 1
236 object = sorted(object, key=_safe_key)
237 self._format_items(object, stream, indent, allowance + len(endchar),
238 context, level)
239 stream.write(endchar)
240
241 _dispatch[set.__repr__] = _pprint_set
242 _dispatch[frozenset.__repr__] = _pprint_set
243
244 def _pprint_str(self, object, stream, indent, allowance, context, level):
245 write = stream.write
246 if not len(object):
247 write(repr(object))
248 return
249 chunks = []
250 lines = object.splitlines(True)
251 if level == 1:
252 indent += 1
253 allowance += 1
254 max_width1 = max_width = self._width - indent
255 for i, line in enumerate(lines):
256 rep = repr(line)
257 if i == len(lines) - 1:
258 max_width1 -= allowance
259 if len(rep) <= max_width1:
260 chunks.append(rep)
261 else:
262 # A list of alternating (non-space, space) strings
263 parts = re.findall(r'\S*\s*', line)
264 assert parts
265 assert not parts[-1]
266 parts.pop() # drop empty last part
267 max_width2 = max_width
268 current = ''
269 for j, part in enumerate(parts):
270 candidate = current + part
271 if j == len(parts) - 1 and i == len(lines) - 1:
272 max_width2 -= allowance
273 if len(repr(candidate)) > max_width2:
Serhiy Storchakafe3dc372014-12-20 20:57:15 +0200274 if current:
275 chunks.append(repr(current))
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200276 current = part
277 else:
278 current = candidate
279 if current:
280 chunks.append(repr(current))
281 if len(chunks) == 1:
282 write(rep)
283 return
284 if level == 1:
285 write('(')
286 for i, rep in enumerate(chunks):
287 if i > 0:
288 write('\n' + ' '*indent)
289 write(rep)
290 if level == 1:
291 write(')')
292
293 _dispatch[str.__repr__] = _pprint_str
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000294
Serhiy Storchaka022f2032015-03-24 19:22:37 +0200295 def _pprint_bytes(self, object, stream, indent, allowance, context, level):
296 write = stream.write
297 if len(object) <= 4:
298 write(repr(object))
299 return
300 parens = level == 1
301 if parens:
302 indent += 1
303 allowance += 1
304 write('(')
305 delim = ''
306 for rep in _wrap_bytes_repr(object, self._width - indent, allowance):
307 write(delim)
308 write(rep)
309 if not delim:
310 delim = '\n' + ' '*indent
311 if parens:
312 write(')')
313
314 _dispatch[bytes.__repr__] = _pprint_bytes
315
316 def _pprint_bytearray(self, object, stream, indent, allowance, context, level):
317 write = stream.write
318 write('bytearray(')
319 self._pprint_bytes(bytes(object), stream, indent + 10,
320 allowance + 1, context, level + 1)
321 write(')')
322
323 _dispatch[bytearray.__repr__] = _pprint_bytearray
324
Serhiy Storchaka87eb4822015-03-24 19:31:50 +0200325 def _pprint_mappingproxy(self, object, stream, indent, allowance, context, level):
326 stream.write('mappingproxy(')
327 self._format(object.copy(), stream, indent + 13, allowance + 1,
328 context, level)
329 stream.write(')')
330
331 _dispatch[_types.MappingProxyType.__repr__] = _pprint_mappingproxy
332
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200333 def _format_dict_items(self, items, stream, indent, allowance, context,
334 level):
335 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200336 indent += self._indent_per_level
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200337 delimnl = ',\n' + ' ' * indent
338 last_index = len(items) - 1
339 for i, (key, ent) in enumerate(items):
340 last = i == last_index
341 rep = self._repr(key, context, level)
342 write(rep)
343 write(': ')
344 self._format(ent, stream, indent + len(rep) + 2,
345 allowance if last else 1,
346 context, level)
347 if not last:
348 write(delimnl)
349
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300350 def _format_items(self, items, stream, indent, allowance, context, level):
351 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200352 indent += self._indent_per_level
353 if self._indent_per_level > 1:
354 write((self._indent_per_level - 1) * ' ')
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300355 delimnl = ',\n' + ' ' * indent
356 delim = ''
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200357 width = max_width = self._width - indent + 1
358 it = iter(items)
359 try:
360 next_ent = next(it)
361 except StopIteration:
362 return
363 last = False
364 while not last:
365 ent = next_ent
366 try:
367 next_ent = next(it)
368 except StopIteration:
369 last = True
370 max_width -= allowance
371 width -= allowance
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300372 if self._compact:
373 rep = self._repr(ent, context, level)
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200374 w = len(rep) + 2
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300375 if width < w:
376 width = max_width
377 if delim:
378 delim = delimnl
379 if width >= w:
380 width -= w
381 write(delim)
382 delim = ', '
383 write(rep)
384 continue
385 write(delim)
386 delim = delimnl
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200387 self._format(ent, stream, indent,
388 allowance if last else 1,
389 context, level)
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300390
Fred Drakee6691ef2002-07-08 12:28:06 +0000391 def _repr(self, object, context, level):
Fred Drakeaee113d2002-04-02 05:08:35 +0000392 repr, readable, recursive = self.format(object, context.copy(),
Fred Drakee6691ef2002-07-08 12:28:06 +0000393 self._depth, level)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000394 if not readable:
Fred Drakee6691ef2002-07-08 12:28:06 +0000395 self._readable = False
Tim Petersa814db52001-05-14 07:05:58 +0000396 if recursive:
Fred Drakee6691ef2002-07-08 12:28:06 +0000397 self._recursive = True
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000398 return repr
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000399
Fred Drakeaee113d2002-04-02 05:08:35 +0000400 def format(self, object, context, maxlevels, level):
401 """Format object for a specific context, returning a string
402 and flags indicating whether the representation is 'readable'
403 and whether the object represents a recursive construct.
404 """
405 return _safe_repr(object, context, maxlevels, level)
406
Serhiy Storchakabedbf962015-05-12 13:35:48 +0300407 def _pprint_default_dict(self, object, stream, indent, allowance, context, level):
408 if not len(object):
409 stream.write(repr(object))
410 return
411 rdf = self._repr(object.default_factory, context, level)
412 cls = object.__class__
413 indent += len(cls.__name__) + 1
414 stream.write('%s(%s,\n%s' % (cls.__name__, rdf, ' ' * indent))
415 self._pprint_dict(object, stream, indent, allowance + 1, context, level)
416 stream.write(')')
417
418 _dispatch[_collections.defaultdict.__repr__] = _pprint_default_dict
419
420 def _pprint_counter(self, object, stream, indent, allowance, context, level):
421 if not len(object):
422 stream.write(repr(object))
423 return
424 cls = object.__class__
425 stream.write(cls.__name__ + '({')
426 if self._indent_per_level > 1:
427 stream.write((self._indent_per_level - 1) * ' ')
428 items = object.most_common()
429 self._format_dict_items(items, stream,
430 indent + len(cls.__name__) + 1, allowance + 2,
431 context, level)
432 stream.write('})')
433
434 _dispatch[_collections.Counter.__repr__] = _pprint_counter
435
436 def _pprint_chain_map(self, object, stream, indent, allowance, context, level):
437 if not len(object.maps):
438 stream.write(repr(object))
439 return
440 cls = object.__class__
441 stream.write(cls.__name__ + '(')
442 indent += len(cls.__name__) + 1
443 for i, m in enumerate(object.maps):
444 if i == len(object.maps) - 1:
445 self._format(m, stream, indent, allowance + 1, context, level)
446 stream.write(')')
447 else:
448 self._format(m, stream, indent, 1, context, level)
449 stream.write(',\n' + ' ' * indent)
450
451 _dispatch[_collections.ChainMap.__repr__] = _pprint_chain_map
452
453 def _pprint_deque(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 indent += len(cls.__name__) + 1
460 stream.write('[')
461 if object.maxlen is None:
462 self._format_items(object, stream, indent, allowance + 2,
463 context, level)
464 stream.write('])')
465 else:
466 self._format_items(object, stream, indent, 2,
467 context, level)
468 rml = self._repr(object.maxlen, context, level)
469 stream.write('],\n%smaxlen=%s)' % (' ' * indent, rml))
470
471 _dispatch[_collections.deque.__repr__] = _pprint_deque
472
473 def _pprint_user_dict(self, object, stream, indent, allowance, context, level):
474 self._format(object.data, stream, indent, allowance, context, level - 1)
475
476 _dispatch[_collections.UserDict.__repr__] = _pprint_user_dict
477
478 def _pprint_user_list(self, object, stream, indent, allowance, context, level):
479 self._format(object.data, stream, indent, allowance, context, level - 1)
480
481 _dispatch[_collections.UserList.__repr__] = _pprint_user_list
482
483 def _pprint_user_string(self, object, stream, indent, allowance, context, level):
484 self._format(object.data, stream, indent, allowance, context, level - 1)
485
486 _dispatch[_collections.UserString.__repr__] = _pprint_user_string
Fred Drakeaee113d2002-04-02 05:08:35 +0000487
Tim Petersa814db52001-05-14 07:05:58 +0000488# Return triple (repr_string, isreadable, isrecursive).
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000489
Fred Drake49cc01e2001-11-01 17:50:38 +0000490def _safe_repr(object, context, maxlevels, level):
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200491 typ = type(object)
Serhiy Storchaka8eb1f072015-05-16 21:38:05 +0300492 if typ in _builtin_scalars:
493 return repr(object), True, False
Tim Peters95b3f782001-05-14 18:39:41 +0000494
Walter Dörwald1b626ca2004-11-15 13:51:41 +0000495 r = getattr(typ, "__repr__", None)
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000496 if issubclass(typ, dict) and r is dict.__repr__:
Fred Drake49cc01e2001-11-01 17:50:38 +0000497 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000498 return "{}", True, False
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200499 objid = id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000500 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000501 return "{...}", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000502 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000503 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000504 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000505 readable = True
506 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000507 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000508 append = components.append
509 level += 1
510 saferepr = _safe_repr
Raymond Hettingera7da1662009-11-19 01:07:05 +0000511 items = sorted(object.items(), key=_safe_tuple)
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000512 for k, v in items:
Fred Drake49cc01e2001-11-01 17:50:38 +0000513 krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
514 vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
515 append("%s: %s" % (krepr, vrepr))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000516 readable = readable and kreadable and vreadable
Fred Drake49cc01e2001-11-01 17:50:38 +0000517 if krecur or vrecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000518 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000519 del context[objid]
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200520 return "{%s}" % ", ".join(components), readable, recursive
Tim Peters95b3f782001-05-14 18:39:41 +0000521
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000522 if (issubclass(typ, list) and r is list.__repr__) or \
523 (issubclass(typ, tuple) and r is tuple.__repr__):
524 if issubclass(typ, list):
Fred Drake49cc01e2001-11-01 17:50:38 +0000525 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000526 return "[]", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000527 format = "[%s]"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200528 elif len(object) == 1:
Fred Drake49cc01e2001-11-01 17:50:38 +0000529 format = "(%s,)"
530 else:
531 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000532 return "()", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000533 format = "(%s)"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200534 objid = id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000535 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000536 return format % "...", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000537 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000538 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000539 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000540 readable = True
541 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000542 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000543 append = components.append
544 level += 1
545 for o in object:
546 orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)
547 append(orepr)
548 if not oreadable:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000549 readable = False
Fred Drake49cc01e2001-11-01 17:50:38 +0000550 if orecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000551 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000552 del context[objid]
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200553 return format % ", ".join(components), readable, recursive
Tim Peters88768482001-11-13 21:51:26 +0000554
Walter Dörwald70a6b492004-02-12 17:35:32 +0000555 rep = repr(object)
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000556 return rep, (rep and not rep.startswith('<')), False
Tim Peters95b3f782001-05-14 18:39:41 +0000557
Serhiy Storchaka8eb1f072015-05-16 21:38:05 +0300558_builtin_scalars = frozenset({str, bytes, bytearray, int, float, complex,
559 bool, type(None)})
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000560
Fred Drake49cc01e2001-11-01 17:50:38 +0000561def _recursion(object):
562 return ("<Recursion on %s with id=%s>"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200563 % (type(object).__name__, id(object)))
Fred Drakea89fda01997-04-16 16:59:30 +0000564
Fred Drake49cc01e2001-11-01 17:50:38 +0000565
566def _perfcheck(object=None):
567 import time
568 if object is None:
569 object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
570 p = PrettyPrinter()
571 t1 = time.time()
572 _safe_repr(object, {}, None, 0)
573 t2 = time.time()
574 p.pformat(object)
575 t3 = time.time()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000576 print("_safe_repr:", t2 - t1)
577 print("pformat:", t3 - t2)
Fred Drake49cc01e2001-11-01 17:50:38 +0000578
Serhiy Storchaka022f2032015-03-24 19:22:37 +0200579def _wrap_bytes_repr(object, width, allowance):
580 current = b''
581 last = len(object) // 4 * 4
582 for i in range(0, len(object), 4):
583 part = object[i: i+4]
584 candidate = current + part
585 if i == last:
586 width -= allowance
587 if len(repr(candidate)) > width:
588 if current:
589 yield repr(current)
590 current = part
591 else:
592 current = candidate
593 if current:
594 yield repr(current)
595
Fred Drake49cc01e2001-11-01 17:50:38 +0000596if __name__ == "__main__":
597 _perfcheck()