blob: 9031a0b6ef03ed2c3398c0c073e1b72e2051ae3f [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
Antoine Pitrou64c16c32013-03-23 20:30:39 +010037import re
Fred Drake397b6152002-12-31 07:14:18 +000038import sys as _sys
Serhiy Storchaka87eb4822015-03-24 19:31:50 +020039import types as _types
Raymond Hettingerbad3c882010-09-09 12:31:00 +000040from collections import OrderedDict as _OrderedDict
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:
89 rv = self.obj.__lt__(other.obj)
90 except TypeError:
91 rv = NotImplemented
92
Raymond Hettingera7da1662009-11-19 01:07:05 +000093 if rv is NotImplemented:
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +020094 rv = (str(type(self.obj)), id(self.obj)) < \
95 (str(type(other.obj)), id(other.obj))
Raymond Hettingera7da1662009-11-19 01:07:05 +000096 return rv
97
98def _safe_tuple(t):
99 "Helper function for comparing 2-tuples"
100 return _safe_key(t[0]), _safe_key(t[1])
101
Fred Drakea89fda01997-04-16 16:59:30 +0000102class PrettyPrinter:
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300103 def __init__(self, indent=1, width=80, depth=None, stream=None, *,
104 compact=False):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000105 """Handle pretty printing operations onto a stream using a set of
106 configured parameters.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000107
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000108 indent
109 Number of spaces to indent for each level of nesting.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000110
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000111 width
112 Attempted maximum number of columns in the output.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000113
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000114 depth
115 The maximum depth to print out nested structures.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000116
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000117 stream
118 The desired output stream. If omitted (or false), the standard
119 output stream available at construction will be used.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000120
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300121 compact
122 If true, several items will be combined in one line.
123
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000124 """
125 indent = int(indent)
126 width = int(width)
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000127 assert indent >= 0, "indent must be >= 0"
Tim Petersa814db52001-05-14 07:05:58 +0000128 assert depth is None or depth > 0, "depth must be > 0"
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000129 assert width, "width must be != 0"
Fred Drakee6691ef2002-07-08 12:28:06 +0000130 self._depth = depth
131 self._indent_per_level = indent
132 self._width = width
Raymond Hettinger16e3c422002-06-01 16:07:16 +0000133 if stream is not None:
Fred Drakee6691ef2002-07-08 12:28:06 +0000134 self._stream = stream
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000135 else:
Fred Drake397b6152002-12-31 07:14:18 +0000136 self._stream = _sys.stdout
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300137 self._compact = bool(compact)
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000138
Fred Drakea89fda01997-04-16 16:59:30 +0000139 def pprint(self, object):
Walter Dörwalde62e9362005-11-11 18:18:51 +0000140 self._format(object, self._stream, 0, 0, {}, 0)
141 self._stream.write("\n")
Fred Drakea89fda01997-04-16 16:59:30 +0000142
143 def pformat(self, object):
Fred Drake397b6152002-12-31 07:14:18 +0000144 sio = _StringIO()
Fred Drakee6691ef2002-07-08 12:28:06 +0000145 self._format(object, sio, 0, 0, {}, 0)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000146 return sio.getvalue()
Fred Drakea89fda01997-04-16 16:59:30 +0000147
Fred Drakee0ffabe1997-07-18 20:42:39 +0000148 def isrecursive(self, object):
Fred Drake397b6152002-12-31 07:14:18 +0000149 return self.format(object, {}, 0, 0)[2]
Fred Drakee0ffabe1997-07-18 20:42:39 +0000150
151 def isreadable(self, object):
Fred Drake397b6152002-12-31 07:14:18 +0000152 s, readable, recursive = self.format(object, {}, 0, 0)
Fred Drakeaee113d2002-04-02 05:08:35 +0000153 return readable and not recursive
Fred Drakee0ffabe1997-07-18 20:42:39 +0000154
Fred Drakee6691ef2002-07-08 12:28:06 +0000155 def _format(self, object, stream, indent, allowance, context, level):
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200156 objid = id(object)
Fred Drake49cc01e2001-11-01 17:50:38 +0000157 if objid in context:
158 stream.write(_recursion(object))
Fred Drakee6691ef2002-07-08 12:28:06 +0000159 self._recursive = True
160 self._readable = False
Fred Drake49cc01e2001-11-01 17:50:38 +0000161 return
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200162 rep = self._repr(object, context, level)
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200163 max_width = self._width - indent - allowance
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200164 if len(rep) > max_width:
165 p = self._dispatch.get(type(object).__repr__, None)
166 if p is not None:
167 context[objid] = 1
168 p(self, object, stream, indent, allowance, context, level + 1)
169 del context[objid]
170 return
171 elif isinstance(object, dict):
172 context[objid] = 1
173 self._pprint_dict(object, stream, indent, allowance,
174 context, level + 1)
175 del context[objid]
176 return
177 stream.write(rep)
178
179 _dispatch = {}
180
181 def _pprint_dict(self, object, stream, indent, allowance, context, level):
Fred Drake49cc01e2001-11-01 17:50:38 +0000182 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200183 write('{')
184 if self._indent_per_level > 1:
185 write((self._indent_per_level - 1) * ' ')
186 length = len(object)
187 if length:
188 if isinstance(object, _OrderedDict):
189 items = list(object.items())
190 else:
191 items = sorted(object.items(), key=_safe_tuple)
192 self._format_dict_items(items, stream, indent, allowance + 1,
193 context, level)
194 write('}')
Fred Drakea89fda01997-04-16 16:59:30 +0000195
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200196 _dispatch[dict.__repr__] = _pprint_dict
197 _dispatch[_OrderedDict.__repr__] = _pprint_dict
Fred Drakea89fda01997-04-16 16:59:30 +0000198
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200199 def _pprint_list(self, object, stream, indent, allowance, context, level):
200 stream.write('[')
201 self._format_items(object, stream, indent, allowance + 1,
202 context, level)
203 stream.write(']')
Fred Drakea89fda01997-04-16 16:59:30 +0000204
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200205 _dispatch[list.__repr__] = _pprint_list
206
207 def _pprint_tuple(self, object, stream, indent, allowance, context, level):
208 stream.write('(')
209 endchar = ',)' if len(object) == 1 else ')'
210 self._format_items(object, stream, indent, allowance + len(endchar),
211 context, level)
212 stream.write(endchar)
213
214 _dispatch[tuple.__repr__] = _pprint_tuple
215
216 def _pprint_set(self, object, stream, indent, allowance, context, level):
217 if not len(object):
218 stream.write(repr(object))
219 return
220 typ = object.__class__
221 if typ is set:
222 stream.write('{')
223 endchar = '}'
224 else:
225 stream.write(typ.__name__ + '({')
226 endchar = '})'
227 indent += len(typ.__name__) + 1
228 object = sorted(object, key=_safe_key)
229 self._format_items(object, stream, indent, allowance + len(endchar),
230 context, level)
231 stream.write(endchar)
232
233 _dispatch[set.__repr__] = _pprint_set
234 _dispatch[frozenset.__repr__] = _pprint_set
235
236 def _pprint_str(self, object, stream, indent, allowance, context, level):
237 write = stream.write
238 if not len(object):
239 write(repr(object))
240 return
241 chunks = []
242 lines = object.splitlines(True)
243 if level == 1:
244 indent += 1
245 allowance += 1
246 max_width1 = max_width = self._width - indent
247 for i, line in enumerate(lines):
248 rep = repr(line)
249 if i == len(lines) - 1:
250 max_width1 -= allowance
251 if len(rep) <= max_width1:
252 chunks.append(rep)
253 else:
254 # A list of alternating (non-space, space) strings
255 parts = re.findall(r'\S*\s*', line)
256 assert parts
257 assert not parts[-1]
258 parts.pop() # drop empty last part
259 max_width2 = max_width
260 current = ''
261 for j, part in enumerate(parts):
262 candidate = current + part
263 if j == len(parts) - 1 and i == len(lines) - 1:
264 max_width2 -= allowance
265 if len(repr(candidate)) > max_width2:
Serhiy Storchakafe3dc372014-12-20 20:57:15 +0200266 if current:
267 chunks.append(repr(current))
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200268 current = part
269 else:
270 current = candidate
271 if current:
272 chunks.append(repr(current))
273 if len(chunks) == 1:
274 write(rep)
275 return
276 if level == 1:
277 write('(')
278 for i, rep in enumerate(chunks):
279 if i > 0:
280 write('\n' + ' '*indent)
281 write(rep)
282 if level == 1:
283 write(')')
284
285 _dispatch[str.__repr__] = _pprint_str
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000286
Serhiy Storchaka022f2032015-03-24 19:22:37 +0200287 def _pprint_bytes(self, object, stream, indent, allowance, context, level):
288 write = stream.write
289 if len(object) <= 4:
290 write(repr(object))
291 return
292 parens = level == 1
293 if parens:
294 indent += 1
295 allowance += 1
296 write('(')
297 delim = ''
298 for rep in _wrap_bytes_repr(object, self._width - indent, allowance):
299 write(delim)
300 write(rep)
301 if not delim:
302 delim = '\n' + ' '*indent
303 if parens:
304 write(')')
305
306 _dispatch[bytes.__repr__] = _pprint_bytes
307
308 def _pprint_bytearray(self, object, stream, indent, allowance, context, level):
309 write = stream.write
310 write('bytearray(')
311 self._pprint_bytes(bytes(object), stream, indent + 10,
312 allowance + 1, context, level + 1)
313 write(')')
314
315 _dispatch[bytearray.__repr__] = _pprint_bytearray
316
Serhiy Storchaka87eb4822015-03-24 19:31:50 +0200317 def _pprint_mappingproxy(self, object, stream, indent, allowance, context, level):
318 stream.write('mappingproxy(')
319 self._format(object.copy(), stream, indent + 13, allowance + 1,
320 context, level)
321 stream.write(')')
322
323 _dispatch[_types.MappingProxyType.__repr__] = _pprint_mappingproxy
324
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200325 def _format_dict_items(self, items, stream, indent, allowance, context,
326 level):
327 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200328 indent += self._indent_per_level
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200329 delimnl = ',\n' + ' ' * indent
330 last_index = len(items) - 1
331 for i, (key, ent) in enumerate(items):
332 last = i == last_index
333 rep = self._repr(key, context, level)
334 write(rep)
335 write(': ')
336 self._format(ent, stream, indent + len(rep) + 2,
337 allowance if last else 1,
338 context, level)
339 if not last:
340 write(delimnl)
341
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300342 def _format_items(self, items, stream, indent, allowance, context, level):
343 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200344 indent += self._indent_per_level
345 if self._indent_per_level > 1:
346 write((self._indent_per_level - 1) * ' ')
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300347 delimnl = ',\n' + ' ' * indent
348 delim = ''
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200349 width = max_width = self._width - indent + 1
350 it = iter(items)
351 try:
352 next_ent = next(it)
353 except StopIteration:
354 return
355 last = False
356 while not last:
357 ent = next_ent
358 try:
359 next_ent = next(it)
360 except StopIteration:
361 last = True
362 max_width -= allowance
363 width -= allowance
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300364 if self._compact:
365 rep = self._repr(ent, context, level)
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200366 w = len(rep) + 2
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300367 if width < w:
368 width = max_width
369 if delim:
370 delim = delimnl
371 if width >= w:
372 width -= w
373 write(delim)
374 delim = ', '
375 write(rep)
376 continue
377 write(delim)
378 delim = delimnl
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200379 self._format(ent, stream, indent,
380 allowance if last else 1,
381 context, level)
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300382
Fred Drakee6691ef2002-07-08 12:28:06 +0000383 def _repr(self, object, context, level):
Fred Drakeaee113d2002-04-02 05:08:35 +0000384 repr, readable, recursive = self.format(object, context.copy(),
Fred Drakee6691ef2002-07-08 12:28:06 +0000385 self._depth, level)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000386 if not readable:
Fred Drakee6691ef2002-07-08 12:28:06 +0000387 self._readable = False
Tim Petersa814db52001-05-14 07:05:58 +0000388 if recursive:
Fred Drakee6691ef2002-07-08 12:28:06 +0000389 self._recursive = True
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000390 return repr
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000391
Fred Drakeaee113d2002-04-02 05:08:35 +0000392 def format(self, object, context, maxlevels, level):
393 """Format object for a specific context, returning a string
394 and flags indicating whether the representation is 'readable'
395 and whether the object represents a recursive construct.
396 """
397 return _safe_repr(object, context, maxlevels, level)
398
399
Tim Petersa814db52001-05-14 07:05:58 +0000400# Return triple (repr_string, isreadable, isrecursive).
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000401
Fred Drake49cc01e2001-11-01 17:50:38 +0000402def _safe_repr(object, context, maxlevels, level):
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200403 typ = type(object)
Martin v. Löwisd02879d2003-06-07 20:47:37 +0000404 if typ is str:
Fred Drake397b6152002-12-31 07:14:18 +0000405 if 'locale' not in _sys.modules:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000406 return repr(object), True, False
Fred Drake1ef106c2001-09-04 19:43:26 +0000407 if "'" in object and '"' not in object:
408 closure = '"'
409 quotes = {'"': '\\"'}
410 else:
411 closure = "'"
412 quotes = {"'": "\\'"}
Fred Drake49cc01e2001-11-01 17:50:38 +0000413 qget = quotes.get
Fred Drake397b6152002-12-31 07:14:18 +0000414 sio = _StringIO()
Fred Drake49cc01e2001-11-01 17:50:38 +0000415 write = sio.write
Fred Drake1ef106c2001-09-04 19:43:26 +0000416 for char in object:
417 if char.isalpha():
Fred Drake49cc01e2001-11-01 17:50:38 +0000418 write(char)
Fred Drake1ef106c2001-09-04 19:43:26 +0000419 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000420 write(qget(char, repr(char)[1:-1]))
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000421 return ("%s%s%s" % (closure, sio.getvalue(), closure)), True, False
Tim Peters95b3f782001-05-14 18:39:41 +0000422
Walter Dörwald1b626ca2004-11-15 13:51:41 +0000423 r = getattr(typ, "__repr__", None)
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000424 if issubclass(typ, dict) and r is dict.__repr__:
Fred Drake49cc01e2001-11-01 17:50:38 +0000425 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000426 return "{}", True, False
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200427 objid = id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000428 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000429 return "{...}", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000430 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000431 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000432 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000433 readable = True
434 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000435 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000436 append = components.append
437 level += 1
438 saferepr = _safe_repr
Raymond Hettingera7da1662009-11-19 01:07:05 +0000439 items = sorted(object.items(), key=_safe_tuple)
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000440 for k, v in items:
Fred Drake49cc01e2001-11-01 17:50:38 +0000441 krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
442 vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
443 append("%s: %s" % (krepr, vrepr))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000444 readable = readable and kreadable and vreadable
Fred Drake49cc01e2001-11-01 17:50:38 +0000445 if krecur or vrecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000446 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000447 del context[objid]
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200448 return "{%s}" % ", ".join(components), readable, recursive
Tim Peters95b3f782001-05-14 18:39:41 +0000449
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000450 if (issubclass(typ, list) and r is list.__repr__) or \
451 (issubclass(typ, tuple) and r is tuple.__repr__):
452 if issubclass(typ, list):
Fred Drake49cc01e2001-11-01 17:50:38 +0000453 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000454 return "[]", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000455 format = "[%s]"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200456 elif len(object) == 1:
Fred Drake49cc01e2001-11-01 17:50:38 +0000457 format = "(%s,)"
458 else:
459 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000460 return "()", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000461 format = "(%s)"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200462 objid = id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000463 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000464 return format % "...", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000465 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000466 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000467 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000468 readable = True
469 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000470 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000471 append = components.append
472 level += 1
473 for o in object:
474 orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)
475 append(orepr)
476 if not oreadable:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000477 readable = False
Fred Drake49cc01e2001-11-01 17:50:38 +0000478 if orecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000479 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000480 del context[objid]
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200481 return format % ", ".join(components), readable, recursive
Tim Peters88768482001-11-13 21:51:26 +0000482
Walter Dörwald70a6b492004-02-12 17:35:32 +0000483 rep = repr(object)
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000484 return rep, (rep and not rep.startswith('<')), False
Tim Peters95b3f782001-05-14 18:39:41 +0000485
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000486
Fred Drake49cc01e2001-11-01 17:50:38 +0000487def _recursion(object):
488 return ("<Recursion on %s with id=%s>"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200489 % (type(object).__name__, id(object)))
Fred Drakea89fda01997-04-16 16:59:30 +0000490
Fred Drake49cc01e2001-11-01 17:50:38 +0000491
492def _perfcheck(object=None):
493 import time
494 if object is None:
495 object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
496 p = PrettyPrinter()
497 t1 = time.time()
498 _safe_repr(object, {}, None, 0)
499 t2 = time.time()
500 p.pformat(object)
501 t3 = time.time()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000502 print("_safe_repr:", t2 - t1)
503 print("pformat:", t3 - t2)
Fred Drake49cc01e2001-11-01 17:50:38 +0000504
Serhiy Storchaka022f2032015-03-24 19:22:37 +0200505def _wrap_bytes_repr(object, width, allowance):
506 current = b''
507 last = len(object) // 4 * 4
508 for i in range(0, len(object), 4):
509 part = object[i: i+4]
510 candidate = current + part
511 if i == last:
512 width -= allowance
513 if len(repr(candidate)) > width:
514 if current:
515 yield repr(current)
516 current = part
517 else:
518 current = candidate
519 if current:
520 yield repr(current)
521
Fred Drake49cc01e2001-11-01 17:50:38 +0000522if __name__ == "__main__":
523 _perfcheck()