blob: 3be9c3625401ea8ca7c534c371245c9293c28f97 [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):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000155 level = level + 1
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200156 objid = id(object)
Fred Drake49cc01e2001-11-01 17:50:38 +0000157 if objid in context:
158 stream.write(_recursion(object))
Fred Drakee6691ef2002-07-08 12:28:06 +0000159 self._recursive = True
160 self._readable = False
Fred Drake49cc01e2001-11-01 17:50:38 +0000161 return
Fred Drakee6691ef2002-07-08 12:28:06 +0000162 rep = self._repr(object, context, level - 1)
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200163 typ = type(object)
Antoine Pitrou64c16c32013-03-23 20:30:39 +0100164 max_width = self._width - 1 - indent - allowance
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200165 sepLines = len(rep) > max_width
Fred Drake49cc01e2001-11-01 17:50:38 +0000166 write = stream.write
Fred Drakea89fda01997-04-16 16:59:30 +0000167
Fred Drake49cc01e2001-11-01 17:50:38 +0000168 if sepLines:
Walter Dörwald1b626ca2004-11-15 13:51:41 +0000169 r = getattr(typ, "__repr__", None)
Raymond Hettingerbad3c882010-09-09 12:31:00 +0000170 if issubclass(typ, dict):
Fred Drake49cc01e2001-11-01 17:50:38 +0000171 write('{')
Fred Drakee6691ef2002-07-08 12:28:06 +0000172 if self._indent_per_level > 1:
173 write((self._indent_per_level - 1) * ' ')
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200174 length = len(object)
Fred Drake49cc01e2001-11-01 17:50:38 +0000175 if length:
176 context[objid] = 1
Fred Drakee6691ef2002-07-08 12:28:06 +0000177 indent = indent + self._indent_per_level
Raymond Hettingerbad3c882010-09-09 12:31:00 +0000178 if issubclass(typ, _OrderedDict):
179 items = list(object.items())
180 else:
181 items = sorted(object.items(), key=_safe_tuple)
Fred Drake49cc01e2001-11-01 17:50:38 +0000182 key, ent = items[0]
Fred Drakee6691ef2002-07-08 12:28:06 +0000183 rep = self._repr(key, context, level)
Fred Drake49cc01e2001-11-01 17:50:38 +0000184 write(rep)
185 write(': ')
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200186 self._format(ent, stream, indent + len(rep) + 2,
Fred Drake49cc01e2001-11-01 17:50:38 +0000187 allowance + 1, context, level)
188 if length > 1:
189 for key, ent in items[1:]:
Fred Drakee6691ef2002-07-08 12:28:06 +0000190 rep = self._repr(key, context, level)
Barry Warsaw00859c02001-11-28 05:49:39 +0000191 write(',\n%s%s: ' % (' '*indent, rep))
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200192 self._format(ent, stream, indent + len(rep) + 2,
Fred Drake49cc01e2001-11-01 17:50:38 +0000193 allowance + 1, context, level)
Fred Drakee6691ef2002-07-08 12:28:06 +0000194 indent = indent - self._indent_per_level
Fred Drake49cc01e2001-11-01 17:50:38 +0000195 del context[objid]
196 write('}')
197 return
Fred Drakea89fda01997-04-16 16:59:30 +0000198
Christian Heimes1af737c2008-01-23 08:24:23 +0000199 if ((issubclass(typ, list) and r is list.__repr__) or
200 (issubclass(typ, tuple) and r is tuple.__repr__) or
201 (issubclass(typ, set) and r is set.__repr__) or
202 (issubclass(typ, frozenset) and r is frozenset.__repr__)
203 ):
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200204 length = len(object)
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000205 if issubclass(typ, list):
Fred Drake49cc01e2001-11-01 17:50:38 +0000206 write('[')
207 endchar = ']'
Serhiy Storchaka51844382013-10-02 11:40:49 +0300208 elif issubclass(typ, tuple):
Fred Drake49cc01e2001-11-01 17:50:38 +0000209 write('(')
210 endchar = ')'
Serhiy Storchaka51844382013-10-02 11:40:49 +0300211 else:
212 if not length:
213 write(rep)
214 return
215 if typ is set:
216 write('{')
217 endchar = '}'
218 else:
219 write(typ.__name__)
220 write('({')
221 endchar = '})'
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200222 indent += len(typ.__name__) + 1
Serhiy Storchaka51844382013-10-02 11:40:49 +0300223 object = sorted(object, key=_safe_key)
Fred Drakee6691ef2002-07-08 12:28:06 +0000224 if self._indent_per_level > 1:
225 write((self._indent_per_level - 1) * ' ')
Fred Drake49cc01e2001-11-01 17:50:38 +0000226 if length:
227 context[objid] = 1
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300228 self._format_items(object, stream,
229 indent + self._indent_per_level,
230 allowance + 1, context, level)
Fred Drake49cc01e2001-11-01 17:50:38 +0000231 del context[objid]
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000232 if issubclass(typ, tuple) and length == 1:
Fred Drake49cc01e2001-11-01 17:50:38 +0000233 write(',')
234 write(endchar)
235 return
Fred Drakea89fda01997-04-16 16:59:30 +0000236
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200237 if issubclass(typ, str) and len(object) > 0 and r is str.__repr__:
Antoine Pitrou64c16c32013-03-23 20:30:39 +0100238 def _str_parts(s):
239 """
240 Return a list of string literals comprising the repr()
241 of the given string using literal concatenation.
242 """
243 lines = s.splitlines(True)
244 for i, line in enumerate(lines):
245 rep = repr(line)
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200246 if len(rep) <= max_width:
Antoine Pitrou64c16c32013-03-23 20:30:39 +0100247 yield rep
248 else:
249 # A list of alternating (non-space, space) strings
250 parts = re.split(r'(\s+)', line) + ['']
251 current = ''
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200252 for i in range(0, len(parts), 2):
Antoine Pitrou64c16c32013-03-23 20:30:39 +0100253 part = parts[i] + parts[i+1]
254 candidate = current + part
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200255 if len(repr(candidate)) > max_width:
Antoine Pitrou64c16c32013-03-23 20:30:39 +0100256 if current:
257 yield repr(current)
258 current = part
259 else:
260 current = candidate
261 if current:
262 yield repr(current)
263 for i, rep in enumerate(_str_parts(object)):
264 if i > 0:
265 write('\n' + ' '*indent)
266 write(rep)
267 return
Fred Drake49cc01e2001-11-01 17:50:38 +0000268 write(rep)
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000269
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300270 def _format_items(self, items, stream, indent, allowance, context, level):
271 write = stream.write
272 delimnl = ',\n' + ' ' * indent
273 delim = ''
274 width = max_width = self._width - indent - allowance + 2
275 for ent in items:
276 if self._compact:
277 rep = self._repr(ent, context, level)
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200278 w = len(rep) + 2
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300279 if width < w:
280 width = max_width
281 if delim:
282 delim = delimnl
283 if width >= w:
284 width -= w
285 write(delim)
286 delim = ', '
287 write(rep)
288 continue
289 write(delim)
290 delim = delimnl
291 self._format(ent, stream, indent, allowance, context, level)
292
Fred Drakee6691ef2002-07-08 12:28:06 +0000293 def _repr(self, object, context, level):
Fred Drakeaee113d2002-04-02 05:08:35 +0000294 repr, readable, recursive = self.format(object, context.copy(),
Fred Drakee6691ef2002-07-08 12:28:06 +0000295 self._depth, level)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000296 if not readable:
Fred Drakee6691ef2002-07-08 12:28:06 +0000297 self._readable = False
Tim Petersa814db52001-05-14 07:05:58 +0000298 if recursive:
Fred Drakee6691ef2002-07-08 12:28:06 +0000299 self._recursive = True
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000300 return repr
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000301
Fred Drakeaee113d2002-04-02 05:08:35 +0000302 def format(self, object, context, maxlevels, level):
303 """Format object for a specific context, returning a string
304 and flags indicating whether the representation is 'readable'
305 and whether the object represents a recursive construct.
306 """
307 return _safe_repr(object, context, maxlevels, level)
308
309
Tim Petersa814db52001-05-14 07:05:58 +0000310# Return triple (repr_string, isreadable, isrecursive).
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000311
Fred Drake49cc01e2001-11-01 17:50:38 +0000312def _safe_repr(object, context, maxlevels, level):
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200313 typ = type(object)
Martin v. Löwisd02879d2003-06-07 20:47:37 +0000314 if typ is str:
Fred Drake397b6152002-12-31 07:14:18 +0000315 if 'locale' not in _sys.modules:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000316 return repr(object), True, False
Fred Drake1ef106c2001-09-04 19:43:26 +0000317 if "'" in object and '"' not in object:
318 closure = '"'
319 quotes = {'"': '\\"'}
320 else:
321 closure = "'"
322 quotes = {"'": "\\'"}
Fred Drake49cc01e2001-11-01 17:50:38 +0000323 qget = quotes.get
Fred Drake397b6152002-12-31 07:14:18 +0000324 sio = _StringIO()
Fred Drake49cc01e2001-11-01 17:50:38 +0000325 write = sio.write
Fred Drake1ef106c2001-09-04 19:43:26 +0000326 for char in object:
327 if char.isalpha():
Fred Drake49cc01e2001-11-01 17:50:38 +0000328 write(char)
Fred Drake1ef106c2001-09-04 19:43:26 +0000329 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000330 write(qget(char, repr(char)[1:-1]))
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000331 return ("%s%s%s" % (closure, sio.getvalue(), closure)), True, False
Tim Peters95b3f782001-05-14 18:39:41 +0000332
Walter Dörwald1b626ca2004-11-15 13:51:41 +0000333 r = getattr(typ, "__repr__", None)
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000334 if issubclass(typ, dict) and r is dict.__repr__:
Fred Drake49cc01e2001-11-01 17:50:38 +0000335 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000336 return "{}", True, False
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200337 objid = id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000338 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000339 return "{...}", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000340 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000341 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000342 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000343 readable = True
344 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000345 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000346 append = components.append
347 level += 1
348 saferepr = _safe_repr
Raymond Hettingera7da1662009-11-19 01:07:05 +0000349 items = sorted(object.items(), key=_safe_tuple)
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000350 for k, v in items:
Fred Drake49cc01e2001-11-01 17:50:38 +0000351 krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
352 vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
353 append("%s: %s" % (krepr, vrepr))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000354 readable = readable and kreadable and vreadable
Fred Drake49cc01e2001-11-01 17:50:38 +0000355 if krecur or vrecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000356 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000357 del context[objid]
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200358 return "{%s}" % ", ".join(components), readable, recursive
Tim Peters95b3f782001-05-14 18:39:41 +0000359
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000360 if (issubclass(typ, list) and r is list.__repr__) or \
361 (issubclass(typ, tuple) and r is tuple.__repr__):
362 if issubclass(typ, list):
Fred Drake49cc01e2001-11-01 17:50:38 +0000363 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000364 return "[]", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000365 format = "[%s]"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200366 elif len(object) == 1:
Fred Drake49cc01e2001-11-01 17:50:38 +0000367 format = "(%s,)"
368 else:
369 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000370 return "()", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000371 format = "(%s)"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200372 objid = id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000373 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000374 return format % "...", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000375 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000376 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000377 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000378 readable = True
379 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000380 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000381 append = components.append
382 level += 1
383 for o in object:
384 orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)
385 append(orepr)
386 if not oreadable:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000387 readable = False
Fred Drake49cc01e2001-11-01 17:50:38 +0000388 if orecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000389 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000390 del context[objid]
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200391 return format % ", ".join(components), readable, recursive
Tim Peters88768482001-11-13 21:51:26 +0000392
Walter Dörwald70a6b492004-02-12 17:35:32 +0000393 rep = repr(object)
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000394 return rep, (rep and not rep.startswith('<')), False
Tim Peters95b3f782001-05-14 18:39:41 +0000395
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000396
Fred Drake49cc01e2001-11-01 17:50:38 +0000397def _recursion(object):
398 return ("<Recursion on %s with id=%s>"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200399 % (type(object).__name__, id(object)))
Fred Drakea89fda01997-04-16 16:59:30 +0000400
Fred Drake49cc01e2001-11-01 17:50:38 +0000401
402def _perfcheck(object=None):
403 import time
404 if object is None:
405 object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
406 p = PrettyPrinter()
407 t1 = time.time()
408 _safe_repr(object, {}, None, 0)
409 t2 = time.time()
410 p.pformat(object)
411 t3 = time.time()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000412 print("_safe_repr:", t2 - t1)
413 print("pformat:", t3 - t2)
Fred Drake49cc01e2001-11-01 17:50:38 +0000414
415if __name__ == "__main__":
416 _perfcheck()