blob: c79c7137566a605f1daf550f6a8ae1d25e878972 [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:
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)
Serhiy Storchakaf3fa3082015-03-26 08:43:21 +0200127 if indent < 0:
128 raise ValueError('indent must be >= 0')
129 if depth is not None and depth <= 0:
130 raise ValueError('depth must be > 0')
131 if not width:
132 raise ValueError('width must be != 0')
Fred Drakee6691ef2002-07-08 12:28:06 +0000133 self._depth = depth
134 self._indent_per_level = indent
135 self._width = width
Raymond Hettinger16e3c422002-06-01 16:07:16 +0000136 if stream is not None:
Fred Drakee6691ef2002-07-08 12:28:06 +0000137 self._stream = stream
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000138 else:
Fred Drake397b6152002-12-31 07:14:18 +0000139 self._stream = _sys.stdout
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300140 self._compact = bool(compact)
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000141
Fred Drakea89fda01997-04-16 16:59:30 +0000142 def pprint(self, object):
Walter Dörwalde62e9362005-11-11 18:18:51 +0000143 self._format(object, self._stream, 0, 0, {}, 0)
144 self._stream.write("\n")
Fred Drakea89fda01997-04-16 16:59:30 +0000145
146 def pformat(self, object):
Fred Drake397b6152002-12-31 07:14:18 +0000147 sio = _StringIO()
Fred Drakee6691ef2002-07-08 12:28:06 +0000148 self._format(object, sio, 0, 0, {}, 0)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000149 return sio.getvalue()
Fred Drakea89fda01997-04-16 16:59:30 +0000150
Fred Drakee0ffabe1997-07-18 20:42:39 +0000151 def isrecursive(self, object):
Fred Drake397b6152002-12-31 07:14:18 +0000152 return self.format(object, {}, 0, 0)[2]
Fred Drakee0ffabe1997-07-18 20:42:39 +0000153
154 def isreadable(self, object):
Fred Drake397b6152002-12-31 07:14:18 +0000155 s, readable, recursive = self.format(object, {}, 0, 0)
Fred Drakeaee113d2002-04-02 05:08:35 +0000156 return readable and not recursive
Fred Drakee0ffabe1997-07-18 20:42:39 +0000157
Fred Drakee6691ef2002-07-08 12:28:06 +0000158 def _format(self, object, stream, indent, allowance, context, level):
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200159 objid = id(object)
Fred Drake49cc01e2001-11-01 17:50:38 +0000160 if objid in context:
161 stream.write(_recursion(object))
Fred Drakee6691ef2002-07-08 12:28:06 +0000162 self._recursive = True
163 self._readable = False
Fred Drake49cc01e2001-11-01 17:50:38 +0000164 return
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200165 rep = self._repr(object, context, level)
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200166 max_width = self._width - indent - allowance
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200167 if len(rep) > max_width:
168 p = self._dispatch.get(type(object).__repr__, None)
169 if p is not None:
170 context[objid] = 1
171 p(self, object, stream, indent, allowance, context, level + 1)
172 del context[objid]
173 return
174 elif isinstance(object, dict):
175 context[objid] = 1
176 self._pprint_dict(object, stream, indent, allowance,
177 context, level + 1)
178 del context[objid]
179 return
180 stream.write(rep)
181
182 _dispatch = {}
183
184 def _pprint_dict(self, object, stream, indent, allowance, context, level):
Fred Drake49cc01e2001-11-01 17:50:38 +0000185 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200186 write('{')
187 if self._indent_per_level > 1:
188 write((self._indent_per_level - 1) * ' ')
189 length = len(object)
190 if length:
Serhiy Storchakaaa4c36f2015-03-26 08:51:33 +0200191 items = sorted(object.items(), key=_safe_tuple)
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200192 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
Serhiy Storchakaaa4c36f2015-03-26 08:51:33 +0200197
198 def _pprint_ordered_dict(self, object, stream, indent, allowance, context, level):
199 if not len(object):
200 stream.write(repr(object))
201 return
202 cls = object.__class__
203 stream.write(cls.__name__ + '(')
204 self._format(list(object.items()), stream,
205 indent + len(cls.__name__) + 1, allowance + 1,
206 context, level)
207 stream.write(')')
208
209 _dispatch[_collections.OrderedDict.__repr__] = _pprint_ordered_dict
Fred Drakea89fda01997-04-16 16:59:30 +0000210
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200211 def _pprint_list(self, object, stream, indent, allowance, context, level):
212 stream.write('[')
213 self._format_items(object, stream, indent, allowance + 1,
214 context, level)
215 stream.write(']')
Fred Drakea89fda01997-04-16 16:59:30 +0000216
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200217 _dispatch[list.__repr__] = _pprint_list
218
219 def _pprint_tuple(self, object, stream, indent, allowance, context, level):
220 stream.write('(')
221 endchar = ',)' if len(object) == 1 else ')'
222 self._format_items(object, stream, indent, allowance + len(endchar),
223 context, level)
224 stream.write(endchar)
225
226 _dispatch[tuple.__repr__] = _pprint_tuple
227
228 def _pprint_set(self, object, stream, indent, allowance, context, level):
229 if not len(object):
230 stream.write(repr(object))
231 return
232 typ = object.__class__
233 if typ is set:
234 stream.write('{')
235 endchar = '}'
236 else:
237 stream.write(typ.__name__ + '({')
238 endchar = '})'
239 indent += len(typ.__name__) + 1
240 object = sorted(object, key=_safe_key)
241 self._format_items(object, stream, indent, allowance + len(endchar),
242 context, level)
243 stream.write(endchar)
244
245 _dispatch[set.__repr__] = _pprint_set
246 _dispatch[frozenset.__repr__] = _pprint_set
247
248 def _pprint_str(self, object, stream, indent, allowance, context, level):
249 write = stream.write
250 if not len(object):
251 write(repr(object))
252 return
253 chunks = []
254 lines = object.splitlines(True)
255 if level == 1:
256 indent += 1
257 allowance += 1
258 max_width1 = max_width = self._width - indent
259 for i, line in enumerate(lines):
260 rep = repr(line)
261 if i == len(lines) - 1:
262 max_width1 -= allowance
263 if len(rep) <= max_width1:
264 chunks.append(rep)
265 else:
266 # A list of alternating (non-space, space) strings
267 parts = re.findall(r'\S*\s*', line)
268 assert parts
269 assert not parts[-1]
270 parts.pop() # drop empty last part
271 max_width2 = max_width
272 current = ''
273 for j, part in enumerate(parts):
274 candidate = current + part
275 if j == len(parts) - 1 and i == len(lines) - 1:
276 max_width2 -= allowance
277 if len(repr(candidate)) > max_width2:
Serhiy Storchakafe3dc372014-12-20 20:57:15 +0200278 if current:
279 chunks.append(repr(current))
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200280 current = part
281 else:
282 current = candidate
283 if current:
284 chunks.append(repr(current))
285 if len(chunks) == 1:
286 write(rep)
287 return
288 if level == 1:
289 write('(')
290 for i, rep in enumerate(chunks):
291 if i > 0:
292 write('\n' + ' '*indent)
293 write(rep)
294 if level == 1:
295 write(')')
296
297 _dispatch[str.__repr__] = _pprint_str
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000298
Serhiy Storchaka022f2032015-03-24 19:22:37 +0200299 def _pprint_bytes(self, object, stream, indent, allowance, context, level):
300 write = stream.write
301 if len(object) <= 4:
302 write(repr(object))
303 return
304 parens = level == 1
305 if parens:
306 indent += 1
307 allowance += 1
308 write('(')
309 delim = ''
310 for rep in _wrap_bytes_repr(object, self._width - indent, allowance):
311 write(delim)
312 write(rep)
313 if not delim:
314 delim = '\n' + ' '*indent
315 if parens:
316 write(')')
317
318 _dispatch[bytes.__repr__] = _pprint_bytes
319
320 def _pprint_bytearray(self, object, stream, indent, allowance, context, level):
321 write = stream.write
322 write('bytearray(')
323 self._pprint_bytes(bytes(object), stream, indent + 10,
324 allowance + 1, context, level + 1)
325 write(')')
326
327 _dispatch[bytearray.__repr__] = _pprint_bytearray
328
Serhiy Storchaka87eb4822015-03-24 19:31:50 +0200329 def _pprint_mappingproxy(self, object, stream, indent, allowance, context, level):
330 stream.write('mappingproxy(')
331 self._format(object.copy(), stream, indent + 13, allowance + 1,
332 context, level)
333 stream.write(')')
334
335 _dispatch[_types.MappingProxyType.__repr__] = _pprint_mappingproxy
336
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200337 def _format_dict_items(self, items, stream, indent, allowance, context,
338 level):
339 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200340 indent += self._indent_per_level
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200341 delimnl = ',\n' + ' ' * indent
342 last_index = len(items) - 1
343 for i, (key, ent) in enumerate(items):
344 last = i == last_index
345 rep = self._repr(key, context, level)
346 write(rep)
347 write(': ')
348 self._format(ent, stream, indent + len(rep) + 2,
349 allowance if last else 1,
350 context, level)
351 if not last:
352 write(delimnl)
353
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300354 def _format_items(self, items, stream, indent, allowance, context, level):
355 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200356 indent += self._indent_per_level
357 if self._indent_per_level > 1:
358 write((self._indent_per_level - 1) * ' ')
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300359 delimnl = ',\n' + ' ' * indent
360 delim = ''
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200361 width = max_width = self._width - indent + 1
362 it = iter(items)
363 try:
364 next_ent = next(it)
365 except StopIteration:
366 return
367 last = False
368 while not last:
369 ent = next_ent
370 try:
371 next_ent = next(it)
372 except StopIteration:
373 last = True
374 max_width -= allowance
375 width -= allowance
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300376 if self._compact:
377 rep = self._repr(ent, context, level)
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200378 w = len(rep) + 2
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300379 if width < w:
380 width = max_width
381 if delim:
382 delim = delimnl
383 if width >= w:
384 width -= w
385 write(delim)
386 delim = ', '
387 write(rep)
388 continue
389 write(delim)
390 delim = delimnl
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200391 self._format(ent, stream, indent,
392 allowance if last else 1,
393 context, level)
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300394
Fred Drakee6691ef2002-07-08 12:28:06 +0000395 def _repr(self, object, context, level):
Fred Drakeaee113d2002-04-02 05:08:35 +0000396 repr, readable, recursive = self.format(object, context.copy(),
Fred Drakee6691ef2002-07-08 12:28:06 +0000397 self._depth, level)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000398 if not readable:
Fred Drakee6691ef2002-07-08 12:28:06 +0000399 self._readable = False
Tim Petersa814db52001-05-14 07:05:58 +0000400 if recursive:
Fred Drakee6691ef2002-07-08 12:28:06 +0000401 self._recursive = True
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000402 return repr
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000403
Fred Drakeaee113d2002-04-02 05:08:35 +0000404 def format(self, object, context, maxlevels, level):
405 """Format object for a specific context, returning a string
406 and flags indicating whether the representation is 'readable'
407 and whether the object represents a recursive construct.
408 """
409 return _safe_repr(object, context, maxlevels, level)
410
411
Tim Petersa814db52001-05-14 07:05:58 +0000412# Return triple (repr_string, isreadable, isrecursive).
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000413
Fred Drake49cc01e2001-11-01 17:50:38 +0000414def _safe_repr(object, context, maxlevels, level):
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200415 typ = type(object)
Martin v. Löwisd02879d2003-06-07 20:47:37 +0000416 if typ is str:
Fred Drake397b6152002-12-31 07:14:18 +0000417 if 'locale' not in _sys.modules:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000418 return repr(object), True, False
Fred Drake1ef106c2001-09-04 19:43:26 +0000419 if "'" in object and '"' not in object:
420 closure = '"'
421 quotes = {'"': '\\"'}
422 else:
423 closure = "'"
424 quotes = {"'": "\\'"}
Fred Drake49cc01e2001-11-01 17:50:38 +0000425 qget = quotes.get
Fred Drake397b6152002-12-31 07:14:18 +0000426 sio = _StringIO()
Fred Drake49cc01e2001-11-01 17:50:38 +0000427 write = sio.write
Fred Drake1ef106c2001-09-04 19:43:26 +0000428 for char in object:
429 if char.isalpha():
Fred Drake49cc01e2001-11-01 17:50:38 +0000430 write(char)
Fred Drake1ef106c2001-09-04 19:43:26 +0000431 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000432 write(qget(char, repr(char)[1:-1]))
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000433 return ("%s%s%s" % (closure, sio.getvalue(), closure)), True, False
Tim Peters95b3f782001-05-14 18:39:41 +0000434
Walter Dörwald1b626ca2004-11-15 13:51:41 +0000435 r = getattr(typ, "__repr__", None)
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000436 if issubclass(typ, dict) and r is dict.__repr__:
Fred Drake49cc01e2001-11-01 17:50:38 +0000437 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000438 return "{}", True, False
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200439 objid = id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000440 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000441 return "{...}", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000442 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000443 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000444 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000445 readable = True
446 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000447 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000448 append = components.append
449 level += 1
450 saferepr = _safe_repr
Raymond Hettingera7da1662009-11-19 01:07:05 +0000451 items = sorted(object.items(), key=_safe_tuple)
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000452 for k, v in items:
Fred Drake49cc01e2001-11-01 17:50:38 +0000453 krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
454 vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
455 append("%s: %s" % (krepr, vrepr))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000456 readable = readable and kreadable and vreadable
Fred Drake49cc01e2001-11-01 17:50:38 +0000457 if krecur or vrecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000458 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000459 del context[objid]
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200460 return "{%s}" % ", ".join(components), readable, recursive
Tim Peters95b3f782001-05-14 18:39:41 +0000461
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000462 if (issubclass(typ, list) and r is list.__repr__) or \
463 (issubclass(typ, tuple) and r is tuple.__repr__):
464 if issubclass(typ, list):
Fred Drake49cc01e2001-11-01 17:50:38 +0000465 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000466 return "[]", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000467 format = "[%s]"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200468 elif len(object) == 1:
Fred Drake49cc01e2001-11-01 17:50:38 +0000469 format = "(%s,)"
470 else:
471 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000472 return "()", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000473 format = "(%s)"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200474 objid = id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000475 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000476 return format % "...", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000477 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000478 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000479 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000480 readable = True
481 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000482 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000483 append = components.append
484 level += 1
485 for o in object:
486 orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)
487 append(orepr)
488 if not oreadable:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000489 readable = False
Fred Drake49cc01e2001-11-01 17:50:38 +0000490 if orecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000491 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000492 del context[objid]
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200493 return format % ", ".join(components), readable, recursive
Tim Peters88768482001-11-13 21:51:26 +0000494
Walter Dörwald70a6b492004-02-12 17:35:32 +0000495 rep = repr(object)
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000496 return rep, (rep and not rep.startswith('<')), False
Tim Peters95b3f782001-05-14 18:39:41 +0000497
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000498
Fred Drake49cc01e2001-11-01 17:50:38 +0000499def _recursion(object):
500 return ("<Recursion on %s with id=%s>"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200501 % (type(object).__name__, id(object)))
Fred Drakea89fda01997-04-16 16:59:30 +0000502
Fred Drake49cc01e2001-11-01 17:50:38 +0000503
504def _perfcheck(object=None):
505 import time
506 if object is None:
507 object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
508 p = PrettyPrinter()
509 t1 = time.time()
510 _safe_repr(object, {}, None, 0)
511 t2 = time.time()
512 p.pformat(object)
513 t3 = time.time()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000514 print("_safe_repr:", t2 - t1)
515 print("pformat:", t3 - t2)
Fred Drake49cc01e2001-11-01 17:50:38 +0000516
Serhiy Storchaka022f2032015-03-24 19:22:37 +0200517def _wrap_bytes_repr(object, width, allowance):
518 current = b''
519 last = len(object) // 4 * 4
520 for i in range(0, len(object), 4):
521 part = object[i: i+4]
522 candidate = current + part
523 if i == last:
524 width -= allowance
525 if len(repr(candidate)) > width:
526 if current:
527 yield repr(current)
528 current = part
529 else:
530 current = candidate
531 if current:
532 yield repr(current)
533
Fred Drake49cc01e2001-11-01 17:50:38 +0000534if __name__ == "__main__":
535 _perfcheck()