blob: 2cbffed5d8db508a24b5d94b52f6759c80cc7d65 [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__:
Serhiy Storchakafe3dc372014-12-20 20:57:15 +0200238 chunks = []
239 lines = object.splitlines(True)
240 if level == 1:
241 indent += 1
242 max_width -= 2
243 for i, line in enumerate(lines):
244 rep = repr(line)
245 if len(rep) <= max_width:
246 chunks.append(rep)
247 else:
248 # A list of alternating (non-space, space) strings
249 parts = re.split(r'(\s+)', line) + ['']
250 current = ''
251 for i in range(0, len(parts), 2):
252 part = parts[i] + parts[i+1]
253 candidate = current + part
254 if len(repr(candidate)) > max_width:
255 if current:
256 chunks.append(repr(current))
257 current = part
258 else:
259 current = candidate
260 if current:
261 chunks.append(repr(current))
262 if len(chunks) == 1:
263 write(rep)
264 return
265 if level == 1:
266 write('(')
267 for i, rep in enumerate(chunks):
Antoine Pitrou64c16c32013-03-23 20:30:39 +0100268 if i > 0:
269 write('\n' + ' '*indent)
270 write(rep)
Serhiy Storchakafe3dc372014-12-20 20:57:15 +0200271 if level == 1:
272 write(')')
Antoine Pitrou64c16c32013-03-23 20:30:39 +0100273 return
Fred Drake49cc01e2001-11-01 17:50:38 +0000274 write(rep)
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000275
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300276 def _format_items(self, items, stream, indent, allowance, context, level):
277 write = stream.write
278 delimnl = ',\n' + ' ' * indent
279 delim = ''
280 width = max_width = self._width - indent - allowance + 2
281 for ent in items:
282 if self._compact:
283 rep = self._repr(ent, context, level)
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200284 w = len(rep) + 2
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300285 if width < w:
286 width = max_width
287 if delim:
288 delim = delimnl
289 if width >= w:
290 width -= w
291 write(delim)
292 delim = ', '
293 write(rep)
294 continue
295 write(delim)
296 delim = delimnl
297 self._format(ent, stream, indent, allowance, context, level)
298
Fred Drakee6691ef2002-07-08 12:28:06 +0000299 def _repr(self, object, context, level):
Fred Drakeaee113d2002-04-02 05:08:35 +0000300 repr, readable, recursive = self.format(object, context.copy(),
Fred Drakee6691ef2002-07-08 12:28:06 +0000301 self._depth, level)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000302 if not readable:
Fred Drakee6691ef2002-07-08 12:28:06 +0000303 self._readable = False
Tim Petersa814db52001-05-14 07:05:58 +0000304 if recursive:
Fred Drakee6691ef2002-07-08 12:28:06 +0000305 self._recursive = True
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000306 return repr
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000307
Fred Drakeaee113d2002-04-02 05:08:35 +0000308 def format(self, object, context, maxlevels, level):
309 """Format object for a specific context, returning a string
310 and flags indicating whether the representation is 'readable'
311 and whether the object represents a recursive construct.
312 """
313 return _safe_repr(object, context, maxlevels, level)
314
315
Tim Petersa814db52001-05-14 07:05:58 +0000316# Return triple (repr_string, isreadable, isrecursive).
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000317
Fred Drake49cc01e2001-11-01 17:50:38 +0000318def _safe_repr(object, context, maxlevels, level):
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200319 typ = type(object)
Martin v. Löwisd02879d2003-06-07 20:47:37 +0000320 if typ is str:
Fred Drake397b6152002-12-31 07:14:18 +0000321 if 'locale' not in _sys.modules:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000322 return repr(object), True, False
Fred Drake1ef106c2001-09-04 19:43:26 +0000323 if "'" in object and '"' not in object:
324 closure = '"'
325 quotes = {'"': '\\"'}
326 else:
327 closure = "'"
328 quotes = {"'": "\\'"}
Fred Drake49cc01e2001-11-01 17:50:38 +0000329 qget = quotes.get
Fred Drake397b6152002-12-31 07:14:18 +0000330 sio = _StringIO()
Fred Drake49cc01e2001-11-01 17:50:38 +0000331 write = sio.write
Fred Drake1ef106c2001-09-04 19:43:26 +0000332 for char in object:
333 if char.isalpha():
Fred Drake49cc01e2001-11-01 17:50:38 +0000334 write(char)
Fred Drake1ef106c2001-09-04 19:43:26 +0000335 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000336 write(qget(char, repr(char)[1:-1]))
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000337 return ("%s%s%s" % (closure, sio.getvalue(), closure)), True, False
Tim Peters95b3f782001-05-14 18:39:41 +0000338
Walter Dörwald1b626ca2004-11-15 13:51:41 +0000339 r = getattr(typ, "__repr__", None)
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000340 if issubclass(typ, dict) and r is dict.__repr__:
Fred Drake49cc01e2001-11-01 17:50:38 +0000341 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000342 return "{}", True, False
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200343 objid = id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000344 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000345 return "{...}", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000346 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000347 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000348 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000349 readable = True
350 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000351 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000352 append = components.append
353 level += 1
354 saferepr = _safe_repr
Raymond Hettingera7da1662009-11-19 01:07:05 +0000355 items = sorted(object.items(), key=_safe_tuple)
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000356 for k, v in items:
Fred Drake49cc01e2001-11-01 17:50:38 +0000357 krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
358 vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
359 append("%s: %s" % (krepr, vrepr))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000360 readable = readable and kreadable and vreadable
Fred Drake49cc01e2001-11-01 17:50:38 +0000361 if krecur or vrecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000362 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000363 del context[objid]
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200364 return "{%s}" % ", ".join(components), readable, recursive
Tim Peters95b3f782001-05-14 18:39:41 +0000365
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000366 if (issubclass(typ, list) and r is list.__repr__) or \
367 (issubclass(typ, tuple) and r is tuple.__repr__):
368 if issubclass(typ, list):
Fred Drake49cc01e2001-11-01 17:50:38 +0000369 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 elif len(object) == 1:
Fred Drake49cc01e2001-11-01 17:50:38 +0000373 format = "(%s,)"
374 else:
375 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000376 return "()", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000377 format = "(%s)"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200378 objid = id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000379 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000380 return format % "...", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000381 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000382 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000383 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000384 readable = True
385 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000386 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000387 append = components.append
388 level += 1
389 for o in object:
390 orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)
391 append(orepr)
392 if not oreadable:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000393 readable = False
Fred Drake49cc01e2001-11-01 17:50:38 +0000394 if orecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000395 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000396 del context[objid]
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200397 return format % ", ".join(components), readable, recursive
Tim Peters88768482001-11-13 21:51:26 +0000398
Walter Dörwald70a6b492004-02-12 17:35:32 +0000399 rep = repr(object)
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000400 return rep, (rep and not rep.startswith('<')), False
Tim Peters95b3f782001-05-14 18:39:41 +0000401
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000402
Fred Drake49cc01e2001-11-01 17:50:38 +0000403def _recursion(object):
404 return ("<Recursion on %s with id=%s>"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200405 % (type(object).__name__, id(object)))
Fred Drakea89fda01997-04-16 16:59:30 +0000406
Fred Drake49cc01e2001-11-01 17:50:38 +0000407
408def _perfcheck(object=None):
409 import time
410 if object is None:
411 object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
412 p = PrettyPrinter()
413 t1 = time.time()
414 _safe_repr(object, {}, None, 0)
415 t2 = time.time()
416 p.pformat(object)
417 t3 = time.time()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000418 print("_safe_repr:", t2 - t1)
419 print("pformat:", t3 - t2)
Fred Drake49cc01e2001-11-01 17:50:38 +0000420
421if __name__ == "__main__":
422 _perfcheck()