blob: 723ea9c3dc75cf0a23ce8fa58e74a4529d105a53 [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
407
Tim Petersa814db52001-05-14 07:05:58 +0000408# Return triple (repr_string, isreadable, isrecursive).
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000409
Fred Drake49cc01e2001-11-01 17:50:38 +0000410def _safe_repr(object, context, maxlevels, level):
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200411 typ = type(object)
Martin v. Löwisd02879d2003-06-07 20:47:37 +0000412 if typ is str:
Fred Drake397b6152002-12-31 07:14:18 +0000413 if 'locale' not in _sys.modules:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000414 return repr(object), True, False
Fred Drake1ef106c2001-09-04 19:43:26 +0000415 if "'" in object and '"' not in object:
416 closure = '"'
417 quotes = {'"': '\\"'}
418 else:
419 closure = "'"
420 quotes = {"'": "\\'"}
Fred Drake49cc01e2001-11-01 17:50:38 +0000421 qget = quotes.get
Fred Drake397b6152002-12-31 07:14:18 +0000422 sio = _StringIO()
Fred Drake49cc01e2001-11-01 17:50:38 +0000423 write = sio.write
Fred Drake1ef106c2001-09-04 19:43:26 +0000424 for char in object:
425 if char.isalpha():
Fred Drake49cc01e2001-11-01 17:50:38 +0000426 write(char)
Fred Drake1ef106c2001-09-04 19:43:26 +0000427 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000428 write(qget(char, repr(char)[1:-1]))
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000429 return ("%s%s%s" % (closure, sio.getvalue(), closure)), True, False
Tim Peters95b3f782001-05-14 18:39:41 +0000430
Walter Dörwald1b626ca2004-11-15 13:51:41 +0000431 r = getattr(typ, "__repr__", None)
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000432 if issubclass(typ, dict) and r is dict.__repr__:
Fred Drake49cc01e2001-11-01 17:50:38 +0000433 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000434 return "{}", True, False
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200435 objid = id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000436 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000437 return "{...}", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000438 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000439 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000440 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000441 readable = True
442 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000443 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000444 append = components.append
445 level += 1
446 saferepr = _safe_repr
Raymond Hettingera7da1662009-11-19 01:07:05 +0000447 items = sorted(object.items(), key=_safe_tuple)
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000448 for k, v in items:
Fred Drake49cc01e2001-11-01 17:50:38 +0000449 krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
450 vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
451 append("%s: %s" % (krepr, vrepr))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000452 readable = readable and kreadable and vreadable
Fred Drake49cc01e2001-11-01 17:50:38 +0000453 if krecur or vrecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000454 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000455 del context[objid]
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200456 return "{%s}" % ", ".join(components), readable, recursive
Tim Peters95b3f782001-05-14 18:39:41 +0000457
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000458 if (issubclass(typ, list) and r is list.__repr__) or \
459 (issubclass(typ, tuple) and r is tuple.__repr__):
460 if issubclass(typ, list):
Fred Drake49cc01e2001-11-01 17:50:38 +0000461 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000462 return "[]", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000463 format = "[%s]"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200464 elif len(object) == 1:
Fred Drake49cc01e2001-11-01 17:50:38 +0000465 format = "(%s,)"
466 else:
467 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000468 return "()", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000469 format = "(%s)"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200470 objid = id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000471 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000472 return format % "...", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000473 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000474 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000475 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000476 readable = True
477 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000478 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000479 append = components.append
480 level += 1
481 for o in object:
482 orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)
483 append(orepr)
484 if not oreadable:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000485 readable = False
Fred Drake49cc01e2001-11-01 17:50:38 +0000486 if orecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000487 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000488 del context[objid]
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200489 return format % ", ".join(components), readable, recursive
Tim Peters88768482001-11-13 21:51:26 +0000490
Walter Dörwald70a6b492004-02-12 17:35:32 +0000491 rep = repr(object)
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000492 return rep, (rep and not rep.startswith('<')), False
Tim Peters95b3f782001-05-14 18:39:41 +0000493
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000494
Fred Drake49cc01e2001-11-01 17:50:38 +0000495def _recursion(object):
496 return ("<Recursion on %s with id=%s>"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200497 % (type(object).__name__, id(object)))
Fred Drakea89fda01997-04-16 16:59:30 +0000498
Fred Drake49cc01e2001-11-01 17:50:38 +0000499
500def _perfcheck(object=None):
501 import time
502 if object is None:
503 object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
504 p = PrettyPrinter()
505 t1 = time.time()
506 _safe_repr(object, {}, None, 0)
507 t2 = time.time()
508 p.pformat(object)
509 t3 = time.time()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000510 print("_safe_repr:", t2 - t1)
511 print("pformat:", t3 - t2)
Fred Drake49cc01e2001-11-01 17:50:38 +0000512
Serhiy Storchaka022f2032015-03-24 19:22:37 +0200513def _wrap_bytes_repr(object, width, allowance):
514 current = b''
515 last = len(object) // 4 * 4
516 for i in range(0, len(object), 4):
517 part = object[i: i+4]
518 candidate = current + part
519 if i == last:
520 width -= allowance
521 if len(repr(candidate)) > width:
522 if current:
523 yield repr(current)
524 current = part
525 else:
526 current = candidate
527 if current:
528 yield repr(current)
529
Fred Drake49cc01e2001-11-01 17:50:38 +0000530if __name__ == "__main__":
531 _perfcheck()