blob: 40a485a766975b394dc8b264ea1bfc889c7c8c93 [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 Storchakaa750ce32015-02-14 10:55:19 +0200286 def _format_dict_items(self, items, stream, indent, allowance, context,
287 level):
288 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200289 indent += self._indent_per_level
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200290 delimnl = ',\n' + ' ' * indent
291 last_index = len(items) - 1
292 for i, (key, ent) in enumerate(items):
293 last = i == last_index
294 rep = self._repr(key, context, level)
295 write(rep)
296 write(': ')
297 self._format(ent, stream, indent + len(rep) + 2,
298 allowance if last else 1,
299 context, level)
300 if not last:
301 write(delimnl)
302
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300303 def _format_items(self, items, stream, indent, allowance, context, level):
304 write = stream.write
Serhiy Storchaka8e2aa882015-03-24 18:45:23 +0200305 indent += self._indent_per_level
306 if self._indent_per_level > 1:
307 write((self._indent_per_level - 1) * ' ')
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300308 delimnl = ',\n' + ' ' * indent
309 delim = ''
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200310 width = max_width = self._width - indent + 1
311 it = iter(items)
312 try:
313 next_ent = next(it)
314 except StopIteration:
315 return
316 last = False
317 while not last:
318 ent = next_ent
319 try:
320 next_ent = next(it)
321 except StopIteration:
322 last = True
323 max_width -= allowance
324 width -= allowance
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300325 if self._compact:
326 rep = self._repr(ent, context, level)
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200327 w = len(rep) + 2
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300328 if width < w:
329 width = max_width
330 if delim:
331 delim = delimnl
332 if width >= w:
333 width -= w
334 write(delim)
335 delim = ', '
336 write(rep)
337 continue
338 write(delim)
339 delim = delimnl
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200340 self._format(ent, stream, indent,
341 allowance if last else 1,
342 context, level)
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300343
Fred Drakee6691ef2002-07-08 12:28:06 +0000344 def _repr(self, object, context, level):
Fred Drakeaee113d2002-04-02 05:08:35 +0000345 repr, readable, recursive = self.format(object, context.copy(),
Fred Drakee6691ef2002-07-08 12:28:06 +0000346 self._depth, level)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000347 if not readable:
Fred Drakee6691ef2002-07-08 12:28:06 +0000348 self._readable = False
Tim Petersa814db52001-05-14 07:05:58 +0000349 if recursive:
Fred Drakee6691ef2002-07-08 12:28:06 +0000350 self._recursive = True
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000351 return repr
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000352
Fred Drakeaee113d2002-04-02 05:08:35 +0000353 def format(self, object, context, maxlevels, level):
354 """Format object for a specific context, returning a string
355 and flags indicating whether the representation is 'readable'
356 and whether the object represents a recursive construct.
357 """
358 return _safe_repr(object, context, maxlevels, level)
359
360
Tim Petersa814db52001-05-14 07:05:58 +0000361# Return triple (repr_string, isreadable, isrecursive).
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000362
Fred Drake49cc01e2001-11-01 17:50:38 +0000363def _safe_repr(object, context, maxlevels, level):
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200364 typ = type(object)
Martin v. Löwisd02879d2003-06-07 20:47:37 +0000365 if typ is str:
Fred Drake397b6152002-12-31 07:14:18 +0000366 if 'locale' not in _sys.modules:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000367 return repr(object), True, False
Fred Drake1ef106c2001-09-04 19:43:26 +0000368 if "'" in object and '"' not in object:
369 closure = '"'
370 quotes = {'"': '\\"'}
371 else:
372 closure = "'"
373 quotes = {"'": "\\'"}
Fred Drake49cc01e2001-11-01 17:50:38 +0000374 qget = quotes.get
Fred Drake397b6152002-12-31 07:14:18 +0000375 sio = _StringIO()
Fred Drake49cc01e2001-11-01 17:50:38 +0000376 write = sio.write
Fred Drake1ef106c2001-09-04 19:43:26 +0000377 for char in object:
378 if char.isalpha():
Fred Drake49cc01e2001-11-01 17:50:38 +0000379 write(char)
Fred Drake1ef106c2001-09-04 19:43:26 +0000380 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000381 write(qget(char, repr(char)[1:-1]))
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000382 return ("%s%s%s" % (closure, sio.getvalue(), closure)), True, False
Tim Peters95b3f782001-05-14 18:39:41 +0000383
Walter Dörwald1b626ca2004-11-15 13:51:41 +0000384 r = getattr(typ, "__repr__", None)
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000385 if issubclass(typ, dict) and r is dict.__repr__:
Fred Drake49cc01e2001-11-01 17:50:38 +0000386 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000387 return "{}", True, False
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200388 objid = id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000389 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000390 return "{...}", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000391 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000392 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000393 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000394 readable = True
395 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000396 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000397 append = components.append
398 level += 1
399 saferepr = _safe_repr
Raymond Hettingera7da1662009-11-19 01:07:05 +0000400 items = sorted(object.items(), key=_safe_tuple)
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000401 for k, v in items:
Fred Drake49cc01e2001-11-01 17:50:38 +0000402 krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
403 vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
404 append("%s: %s" % (krepr, vrepr))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000405 readable = readable and kreadable and vreadable
Fred Drake49cc01e2001-11-01 17:50:38 +0000406 if krecur or vrecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000407 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000408 del context[objid]
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200409 return "{%s}" % ", ".join(components), readable, recursive
Tim Peters95b3f782001-05-14 18:39:41 +0000410
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000411 if (issubclass(typ, list) and r is list.__repr__) or \
412 (issubclass(typ, tuple) and r is tuple.__repr__):
413 if issubclass(typ, list):
Fred Drake49cc01e2001-11-01 17:50:38 +0000414 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000415 return "[]", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000416 format = "[%s]"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200417 elif len(object) == 1:
Fred Drake49cc01e2001-11-01 17:50:38 +0000418 format = "(%s,)"
419 else:
420 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000421 return "()", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000422 format = "(%s)"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200423 objid = id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000424 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000425 return format % "...", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000426 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000427 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000428 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000429 readable = True
430 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000431 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000432 append = components.append
433 level += 1
434 for o in object:
435 orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)
436 append(orepr)
437 if not oreadable:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000438 readable = False
Fred Drake49cc01e2001-11-01 17:50:38 +0000439 if orecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000440 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000441 del context[objid]
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200442 return format % ", ".join(components), readable, recursive
Tim Peters88768482001-11-13 21:51:26 +0000443
Walter Dörwald70a6b492004-02-12 17:35:32 +0000444 rep = repr(object)
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000445 return rep, (rep and not rep.startswith('<')), False
Tim Peters95b3f782001-05-14 18:39:41 +0000446
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000447
Fred Drake49cc01e2001-11-01 17:50:38 +0000448def _recursion(object):
449 return ("<Recursion on %s with id=%s>"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200450 % (type(object).__name__, id(object)))
Fred Drakea89fda01997-04-16 16:59:30 +0000451
Fred Drake49cc01e2001-11-01 17:50:38 +0000452
453def _perfcheck(object=None):
454 import time
455 if object is None:
456 object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
457 p = PrettyPrinter()
458 t1 = time.time()
459 _safe_repr(object, {}, None, 0)
460 t2 = time.time()
461 p.pformat(object)
462 t3 = time.time()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000463 print("_safe_repr:", t2 - t1)
464 print("pformat:", t3 - t2)
Fred Drake49cc01e2001-11-01 17:50:38 +0000465
466if __name__ == "__main__":
467 _perfcheck()