blob: bcf2eedebe6b546a9cab0442d68a8e4b3ae57195 [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
Serhiy Storchaka6a7b3a72016-04-17 08:32:47 +030075 The wrapped-object will fallback to a Py2.x style comparison for
Raymond Hettingera7da1662009-11-19 01:07:05 +000076 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()