blob: 5b65f579d9f5d5a7204232f8abd1b9f3b914b4fd [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
Raymond Hettingerbad3c882010-09-09 12:31:00 +000039from collections import OrderedDict as _OrderedDict
Guido van Rossum34d19282007-08-09 01:03:29 +000040from io import StringIO as _StringIO
Guido van Rossum5e92aff1997-04-16 00:49:59 +000041
Skip Montanaroc62c81e2001-02-12 02:00:42 +000042__all__ = ["pprint","pformat","isreadable","isrecursive","saferepr",
43 "PrettyPrinter"]
Guido van Rossum5e92aff1997-04-16 00:49:59 +000044
Fred Drake49cc01e2001-11-01 17:50:38 +000045
Serhiy Storchaka7c411a42013-10-02 11:56:18 +030046def pprint(object, stream=None, indent=1, width=80, depth=None, *,
47 compact=False):
Skip Montanaro2dc0c132004-05-14 16:31:56 +000048 """Pretty-print a Python object to a stream [default is sys.stdout]."""
Walter Dörwaldc8de4582003-12-03 20:26:05 +000049 printer = PrettyPrinter(
Serhiy Storchaka7c411a42013-10-02 11:56:18 +030050 stream=stream, indent=indent, width=width, depth=depth,
51 compact=compact)
Fred Drakea89fda01997-04-16 16:59:30 +000052 printer.pprint(object)
Guido van Rossum5e92aff1997-04-16 00:49:59 +000053
Serhiy Storchaka7c411a42013-10-02 11:56:18 +030054def pformat(object, indent=1, width=80, depth=None, *, compact=False):
Fred Drakea89fda01997-04-16 16:59:30 +000055 """Format a Python object into a pretty-printed representation."""
Serhiy Storchaka7c411a42013-10-02 11:56:18 +030056 return PrettyPrinter(indent=indent, width=width, depth=depth,
57 compact=compact).pformat(object)
Guido van Rossum5e92aff1997-04-16 00:49:59 +000058
Fred Drakea89fda01997-04-16 16:59:30 +000059def saferepr(object):
60 """Version of repr() which can handle recursive data structures."""
Fred Drake49cc01e2001-11-01 17:50:38 +000061 return _safe_repr(object, {}, None, 0)[0]
Guido van Rossum5e92aff1997-04-16 00:49:59 +000062
Tim Petersa814db52001-05-14 07:05:58 +000063def isreadable(object):
64 """Determine if saferepr(object) is readable by eval()."""
Fred Drake49cc01e2001-11-01 17:50:38 +000065 return _safe_repr(object, {}, None, 0)[1]
Tim Petersa814db52001-05-14 07:05:58 +000066
67def isrecursive(object):
68 """Determine if object requires a recursive representation."""
Fred Drake49cc01e2001-11-01 17:50:38 +000069 return _safe_repr(object, {}, None, 0)[2]
Guido van Rossum5e92aff1997-04-16 00:49:59 +000070
Raymond Hettingera7da1662009-11-19 01:07:05 +000071class _safe_key:
72 """Helper function for key functions when sorting unorderable objects.
73
74 The wrapped-object will fallback to an Py2.x style comparison for
75 unorderable types (sorting first comparing the type name and then by
76 the obj ids). Does not work recursively, so dict.items() must have
77 _safe_key applied to both the key and the value.
78
79 """
80
81 __slots__ = ['obj']
82
83 def __init__(self, obj):
84 self.obj = obj
85
86 def __lt__(self, other):
Florent Xiclunad6da90f2012-07-21 11:17:38 +020087 try:
88 rv = self.obj.__lt__(other.obj)
89 except TypeError:
90 rv = NotImplemented
91
Raymond Hettingera7da1662009-11-19 01:07:05 +000092 if rv is NotImplemented:
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +020093 rv = (str(type(self.obj)), id(self.obj)) < \
94 (str(type(other.obj)), id(other.obj))
Raymond Hettingera7da1662009-11-19 01:07:05 +000095 return rv
96
97def _safe_tuple(t):
98 "Helper function for comparing 2-tuples"
99 return _safe_key(t[0]), _safe_key(t[1])
100
Fred Drakea89fda01997-04-16 16:59:30 +0000101class PrettyPrinter:
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300102 def __init__(self, indent=1, width=80, depth=None, stream=None, *,
103 compact=False):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000104 """Handle pretty printing operations onto a stream using a set of
105 configured parameters.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000106
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000107 indent
108 Number of spaces to indent for each level of nesting.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000109
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000110 width
111 Attempted maximum number of columns in the output.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000112
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000113 depth
114 The maximum depth to print out nested structures.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000115
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000116 stream
117 The desired output stream. If omitted (or false), the standard
118 output stream available at construction will be used.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000119
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300120 compact
121 If true, several items will be combined in one line.
122
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000123 """
124 indent = int(indent)
125 width = int(width)
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000126 assert indent >= 0, "indent must be >= 0"
Tim Petersa814db52001-05-14 07:05:58 +0000127 assert depth is None or depth > 0, "depth must be > 0"
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000128 assert width, "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:
187 if isinstance(object, _OrderedDict):
188 items = list(object.items())
189 else:
190 items = sorted(object.items(), key=_safe_tuple)
191 self._format_dict_items(items, stream, indent, allowance + 1,
192 context, level)
193 write('}')
Fred Drakea89fda01997-04-16 16:59:30 +0000194
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200195 _dispatch[dict.__repr__] = _pprint_dict
196 _dispatch[_OrderedDict.__repr__] = _pprint_dict
Fred Drakea89fda01997-04-16 16:59:30 +0000197
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200198 def _pprint_list(self, object, stream, indent, allowance, context, level):
199 stream.write('[')
200 self._format_items(object, stream, indent, allowance + 1,
201 context, level)
202 stream.write(']')
Fred Drakea89fda01997-04-16 16:59:30 +0000203
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200204 _dispatch[list.__repr__] = _pprint_list
205
206 def _pprint_tuple(self, object, stream, indent, allowance, context, level):
207 stream.write('(')
208 endchar = ',)' if len(object) == 1 else ')'
209 self._format_items(object, stream, indent, allowance + len(endchar),
210 context, level)
211 stream.write(endchar)
212
213 _dispatch[tuple.__repr__] = _pprint_tuple
214
215 def _pprint_set(self, object, stream, indent, allowance, context, level):
216 if not len(object):
217 stream.write(repr(object))
218 return
219 typ = object.__class__
220 if typ is set:
221 stream.write('{')
222 endchar = '}'
223 else:
224 stream.write(typ.__name__ + '({')
225 endchar = '})'
226 indent += len(typ.__name__) + 1
227 object = sorted(object, key=_safe_key)
228 self._format_items(object, stream, indent, allowance + len(endchar),
229 context, level)
230 stream.write(endchar)
231
232 _dispatch[set.__repr__] = _pprint_set
233 _dispatch[frozenset.__repr__] = _pprint_set
234
235 def _pprint_str(self, object, stream, indent, allowance, context, level):
236 write = stream.write
237 if not len(object):
238 write(repr(object))
239 return
240 chunks = []
241 lines = object.splitlines(True)
242 if level == 1:
243 indent += 1
244 allowance += 1
245 max_width1 = max_width = self._width - indent
246 for i, line in enumerate(lines):
247 rep = repr(line)
248 if i == len(lines) - 1:
249 max_width1 -= allowance
250 if len(rep) <= max_width1:
251 chunks.append(rep)
252 else:
253 # A list of alternating (non-space, space) strings
254 parts = re.findall(r'\S*\s*', line)
255 assert parts
256 assert not parts[-1]
257 parts.pop() # drop empty last part
258 max_width2 = max_width
259 current = ''
260 for j, part in enumerate(parts):
261 candidate = current + part
262 if j == len(parts) - 1 and i == len(lines) - 1:
263 max_width2 -= allowance
264 if len(repr(candidate)) > max_width2:
Serhiy Storchakafe3dc372014-12-20 20:57:15 +0200265 if current:
266 chunks.append(repr(current))
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200267 current = part
268 else:
269 current = candidate
270 if current:
271 chunks.append(repr(current))
272 if len(chunks) == 1:
273 write(rep)
274 return
275 if level == 1:
276 write('(')
277 for i, rep in enumerate(chunks):
278 if i > 0:
279 write('\n' + ' '*indent)
280 write(rep)
281 if level == 1:
282 write(')')
283
284 _dispatch[str.__repr__] = _pprint_str
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000285
Serhiy Storchaka022f2032015-03-24 19:22:37 +0200286 def _pprint_bytes(self, object, stream, indent, allowance, context, level):
287 write = stream.write
288 if len(object) <= 4:
289 write(repr(object))
290 return
291 parens = level == 1
292 if parens:
293 indent += 1
294 allowance += 1
295 write('(')
296 delim = ''
297 for rep in _wrap_bytes_repr(object, self._width - indent, allowance):
298 write(delim)
299 write(rep)
300 if not delim:
301 delim = '\n' + ' '*indent
302 if parens:
303 write(')')
304
305 _dispatch[bytes.__repr__] = _pprint_bytes
306
307 def _pprint_bytearray(self, object, stream, indent, allowance, context, level):
308 write = stream.write
309 write('bytearray(')
310 self._pprint_bytes(bytes(object), stream, indent + 10,
311 allowance + 1, context, level + 1)
312 write(')')
313
314 _dispatch[bytearray.__repr__] = _pprint_bytearray
315
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200316 def _format_dict_items(self, items, stream, indent, allowance, context,
317 level):
318 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200319 indent += self._indent_per_level
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200320 delimnl = ',\n' + ' ' * indent
321 last_index = len(items) - 1
322 for i, (key, ent) in enumerate(items):
323 last = i == last_index
324 rep = self._repr(key, context, level)
325 write(rep)
326 write(': ')
327 self._format(ent, stream, indent + len(rep) + 2,
328 allowance if last else 1,
329 context, level)
330 if not last:
331 write(delimnl)
332
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300333 def _format_items(self, items, stream, indent, allowance, context, level):
334 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200335 indent += self._indent_per_level
336 if self._indent_per_level > 1:
337 write((self._indent_per_level - 1) * ' ')
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300338 delimnl = ',\n' + ' ' * indent
339 delim = ''
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200340 width = max_width = self._width - indent + 1
341 it = iter(items)
342 try:
343 next_ent = next(it)
344 except StopIteration:
345 return
346 last = False
347 while not last:
348 ent = next_ent
349 try:
350 next_ent = next(it)
351 except StopIteration:
352 last = True
353 max_width -= allowance
354 width -= allowance
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300355 if self._compact:
356 rep = self._repr(ent, context, level)
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200357 w = len(rep) + 2
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300358 if width < w:
359 width = max_width
360 if delim:
361 delim = delimnl
362 if width >= w:
363 width -= w
364 write(delim)
365 delim = ', '
366 write(rep)
367 continue
368 write(delim)
369 delim = delimnl
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200370 self._format(ent, stream, indent,
371 allowance if last else 1,
372 context, level)
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300373
Fred Drakee6691ef2002-07-08 12:28:06 +0000374 def _repr(self, object, context, level):
Fred Drakeaee113d2002-04-02 05:08:35 +0000375 repr, readable, recursive = self.format(object, context.copy(),
Fred Drakee6691ef2002-07-08 12:28:06 +0000376 self._depth, level)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000377 if not readable:
Fred Drakee6691ef2002-07-08 12:28:06 +0000378 self._readable = False
Tim Petersa814db52001-05-14 07:05:58 +0000379 if recursive:
Fred Drakee6691ef2002-07-08 12:28:06 +0000380 self._recursive = True
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000381 return repr
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000382
Fred Drakeaee113d2002-04-02 05:08:35 +0000383 def format(self, object, context, maxlevels, level):
384 """Format object for a specific context, returning a string
385 and flags indicating whether the representation is 'readable'
386 and whether the object represents a recursive construct.
387 """
388 return _safe_repr(object, context, maxlevels, level)
389
390
Tim Petersa814db52001-05-14 07:05:58 +0000391# Return triple (repr_string, isreadable, isrecursive).
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000392
Fred Drake49cc01e2001-11-01 17:50:38 +0000393def _safe_repr(object, context, maxlevels, level):
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200394 typ = type(object)
Martin v. Löwisd02879d2003-06-07 20:47:37 +0000395 if typ is str:
Fred Drake397b6152002-12-31 07:14:18 +0000396 if 'locale' not in _sys.modules:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000397 return repr(object), True, False
Fred Drake1ef106c2001-09-04 19:43:26 +0000398 if "'" in object and '"' not in object:
399 closure = '"'
400 quotes = {'"': '\\"'}
401 else:
402 closure = "'"
403 quotes = {"'": "\\'"}
Fred Drake49cc01e2001-11-01 17:50:38 +0000404 qget = quotes.get
Fred Drake397b6152002-12-31 07:14:18 +0000405 sio = _StringIO()
Fred Drake49cc01e2001-11-01 17:50:38 +0000406 write = sio.write
Fred Drake1ef106c2001-09-04 19:43:26 +0000407 for char in object:
408 if char.isalpha():
Fred Drake49cc01e2001-11-01 17:50:38 +0000409 write(char)
Fred Drake1ef106c2001-09-04 19:43:26 +0000410 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000411 write(qget(char, repr(char)[1:-1]))
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000412 return ("%s%s%s" % (closure, sio.getvalue(), closure)), True, False
Tim Peters95b3f782001-05-14 18:39:41 +0000413
Walter Dörwald1b626ca2004-11-15 13:51:41 +0000414 r = getattr(typ, "__repr__", None)
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000415 if issubclass(typ, dict) and r is dict.__repr__:
Fred Drake49cc01e2001-11-01 17:50:38 +0000416 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000417 return "{}", True, False
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200418 objid = id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000419 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000420 return "{...}", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000421 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000422 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000423 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000424 readable = True
425 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000426 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000427 append = components.append
428 level += 1
429 saferepr = _safe_repr
Raymond Hettingera7da1662009-11-19 01:07:05 +0000430 items = sorted(object.items(), key=_safe_tuple)
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000431 for k, v in items:
Fred Drake49cc01e2001-11-01 17:50:38 +0000432 krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
433 vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
434 append("%s: %s" % (krepr, vrepr))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000435 readable = readable and kreadable and vreadable
Fred Drake49cc01e2001-11-01 17:50:38 +0000436 if krecur or vrecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000437 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000438 del context[objid]
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200439 return "{%s}" % ", ".join(components), readable, recursive
Tim Peters95b3f782001-05-14 18:39:41 +0000440
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000441 if (issubclass(typ, list) and r is list.__repr__) or \
442 (issubclass(typ, tuple) and r is tuple.__repr__):
443 if issubclass(typ, list):
Fred Drake49cc01e2001-11-01 17:50:38 +0000444 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000445 return "[]", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000446 format = "[%s]"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200447 elif len(object) == 1:
Fred Drake49cc01e2001-11-01 17:50:38 +0000448 format = "(%s,)"
449 else:
450 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000451 return "()", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000452 format = "(%s)"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200453 objid = id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000454 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000455 return format % "...", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000456 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000457 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000458 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000459 readable = True
460 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000461 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000462 append = components.append
463 level += 1
464 for o in object:
465 orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)
466 append(orepr)
467 if not oreadable:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000468 readable = False
Fred Drake49cc01e2001-11-01 17:50:38 +0000469 if orecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000470 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000471 del context[objid]
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200472 return format % ", ".join(components), readable, recursive
Tim Peters88768482001-11-13 21:51:26 +0000473
Walter Dörwald70a6b492004-02-12 17:35:32 +0000474 rep = repr(object)
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000475 return rep, (rep and not rep.startswith('<')), False
Tim Peters95b3f782001-05-14 18:39:41 +0000476
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000477
Fred Drake49cc01e2001-11-01 17:50:38 +0000478def _recursion(object):
479 return ("<Recursion on %s with id=%s>"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200480 % (type(object).__name__, id(object)))
Fred Drakea89fda01997-04-16 16:59:30 +0000481
Fred Drake49cc01e2001-11-01 17:50:38 +0000482
483def _perfcheck(object=None):
484 import time
485 if object is None:
486 object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
487 p = PrettyPrinter()
488 t1 = time.time()
489 _safe_repr(object, {}, None, 0)
490 t2 = time.time()
491 p.pformat(object)
492 t3 = time.time()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000493 print("_safe_repr:", t2 - t1)
494 print("pformat:", t3 - t2)
Fred Drake49cc01e2001-11-01 17:50:38 +0000495
Serhiy Storchaka022f2032015-03-24 19:22:37 +0200496def _wrap_bytes_repr(object, width, allowance):
497 current = b''
498 last = len(object) // 4 * 4
499 for i in range(0, len(object), 4):
500 part = object[i: i+4]
501 candidate = current + part
502 if i == last:
503 width -= allowance
504 if len(repr(candidate)) > width:
505 if current:
506 yield repr(current)
507 current = part
508 else:
509 current = candidate
510 if current:
511 yield repr(current)
512
Fred Drake49cc01e2001-11-01 17:50:38 +0000513if __name__ == "__main__":
514 _perfcheck()