blob: 0091e6925ba5c673c4f7d04e104f300bf9a1b70c [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)
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200164 max_width = self._width - 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
Raymond Hettingerbad3c882010-09-09 12:31:00 +0000177 if issubclass(typ, _OrderedDict):
178 items = list(object.items())
179 else:
180 items = sorted(object.items(), key=_safe_tuple)
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200181 self._format_dict_items(items, stream,
182 indent + self._indent_per_level,
183 allowance + 1,
184 context, level)
Fred Drake49cc01e2001-11-01 17:50:38 +0000185 del context[objid]
186 write('}')
187 return
Fred Drakea89fda01997-04-16 16:59:30 +0000188
Christian Heimes1af737c2008-01-23 08:24:23 +0000189 if ((issubclass(typ, list) and r is list.__repr__) or
190 (issubclass(typ, tuple) and r is tuple.__repr__) or
191 (issubclass(typ, set) and r is set.__repr__) or
192 (issubclass(typ, frozenset) and r is frozenset.__repr__)
193 ):
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200194 length = len(object)
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000195 if issubclass(typ, list):
Fred Drake49cc01e2001-11-01 17:50:38 +0000196 write('[')
197 endchar = ']'
Serhiy Storchaka51844382013-10-02 11:40:49 +0300198 elif issubclass(typ, tuple):
Fred Drake49cc01e2001-11-01 17:50:38 +0000199 write('(')
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200200 if length == 1:
201 endchar = ',)'
202 else:
203 endchar = ')'
Serhiy Storchaka51844382013-10-02 11:40:49 +0300204 else:
205 if not length:
206 write(rep)
207 return
208 if typ is set:
209 write('{')
210 endchar = '}'
211 else:
212 write(typ.__name__)
213 write('({')
214 endchar = '})'
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200215 indent += len(typ.__name__) + 1
Serhiy Storchaka51844382013-10-02 11:40:49 +0300216 object = sorted(object, key=_safe_key)
Fred Drakee6691ef2002-07-08 12:28:06 +0000217 if self._indent_per_level > 1:
218 write((self._indent_per_level - 1) * ' ')
Fred Drake49cc01e2001-11-01 17:50:38 +0000219 if length:
220 context[objid] = 1
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300221 self._format_items(object, stream,
222 indent + self._indent_per_level,
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200223 allowance + len(endchar),
224 context, level)
Fred Drake49cc01e2001-11-01 17:50:38 +0000225 del context[objid]
Fred Drake49cc01e2001-11-01 17:50:38 +0000226 write(endchar)
227 return
Fred Drakea89fda01997-04-16 16:59:30 +0000228
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200229 if issubclass(typ, str) and len(object) > 0 and r is str.__repr__:
Serhiy Storchakafe3dc372014-12-20 20:57:15 +0200230 chunks = []
231 lines = object.splitlines(True)
232 if level == 1:
233 indent += 1
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200234 allowance += 1
235 max_width1 = max_width = self._width - indent
Serhiy Storchakafe3dc372014-12-20 20:57:15 +0200236 for i, line in enumerate(lines):
237 rep = repr(line)
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200238 if i == len(lines) - 1:
239 max_width1 -= allowance
240 if len(rep) <= max_width1:
Serhiy Storchakafe3dc372014-12-20 20:57:15 +0200241 chunks.append(rep)
242 else:
243 # A list of alternating (non-space, space) strings
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200244 parts = re.findall(r'\S*\s*', line)
245 assert parts
246 assert not parts[-1]
247 parts.pop() # drop empty last part
248 max_width2 = max_width
Serhiy Storchakafe3dc372014-12-20 20:57:15 +0200249 current = ''
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200250 for j, part in enumerate(parts):
Serhiy Storchakafe3dc372014-12-20 20:57:15 +0200251 candidate = current + part
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200252 if j == len(parts) - 1 and i == len(lines) - 1:
253 max_width2 -= allowance
254 if len(repr(candidate)) > max_width2:
Serhiy Storchakafe3dc372014-12-20 20:57:15 +0200255 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 Storchakaa750ce32015-02-14 10:55:19 +0200276 def _format_dict_items(self, items, stream, indent, allowance, context,
277 level):
278 write = stream.write
279 delimnl = ',\n' + ' ' * indent
280 last_index = len(items) - 1
281 for i, (key, ent) in enumerate(items):
282 last = i == last_index
283 rep = self._repr(key, context, level)
284 write(rep)
285 write(': ')
286 self._format(ent, stream, indent + len(rep) + 2,
287 allowance if last else 1,
288 context, level)
289 if not last:
290 write(delimnl)
291
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300292 def _format_items(self, items, stream, indent, allowance, context, level):
293 write = stream.write
294 delimnl = ',\n' + ' ' * indent
295 delim = ''
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200296 width = max_width = self._width - indent + 1
297 it = iter(items)
298 try:
299 next_ent = next(it)
300 except StopIteration:
301 return
302 last = False
303 while not last:
304 ent = next_ent
305 try:
306 next_ent = next(it)
307 except StopIteration:
308 last = True
309 max_width -= allowance
310 width -= allowance
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300311 if self._compact:
312 rep = self._repr(ent, context, level)
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200313 w = len(rep) + 2
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300314 if width < w:
315 width = max_width
316 if delim:
317 delim = delimnl
318 if width >= w:
319 width -= w
320 write(delim)
321 delim = ', '
322 write(rep)
323 continue
324 write(delim)
325 delim = delimnl
Serhiy Storchakaa750ce32015-02-14 10:55:19 +0200326 self._format(ent, stream, indent,
327 allowance if last else 1,
328 context, level)
Serhiy Storchaka7c411a42013-10-02 11:56:18 +0300329
Fred Drakee6691ef2002-07-08 12:28:06 +0000330 def _repr(self, object, context, level):
Fred Drakeaee113d2002-04-02 05:08:35 +0000331 repr, readable, recursive = self.format(object, context.copy(),
Fred Drakee6691ef2002-07-08 12:28:06 +0000332 self._depth, level)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000333 if not readable:
Fred Drakee6691ef2002-07-08 12:28:06 +0000334 self._readable = False
Tim Petersa814db52001-05-14 07:05:58 +0000335 if recursive:
Fred Drakee6691ef2002-07-08 12:28:06 +0000336 self._recursive = True
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000337 return repr
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000338
Fred Drakeaee113d2002-04-02 05:08:35 +0000339 def format(self, object, context, maxlevels, level):
340 """Format object for a specific context, returning a string
341 and flags indicating whether the representation is 'readable'
342 and whether the object represents a recursive construct.
343 """
344 return _safe_repr(object, context, maxlevels, level)
345
346
Tim Petersa814db52001-05-14 07:05:58 +0000347# Return triple (repr_string, isreadable, isrecursive).
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000348
Fred Drake49cc01e2001-11-01 17:50:38 +0000349def _safe_repr(object, context, maxlevels, level):
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200350 typ = type(object)
Martin v. Löwisd02879d2003-06-07 20:47:37 +0000351 if typ is str:
Fred Drake397b6152002-12-31 07:14:18 +0000352 if 'locale' not in _sys.modules:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000353 return repr(object), True, False
Fred Drake1ef106c2001-09-04 19:43:26 +0000354 if "'" in object and '"' not in object:
355 closure = '"'
356 quotes = {'"': '\\"'}
357 else:
358 closure = "'"
359 quotes = {"'": "\\'"}
Fred Drake49cc01e2001-11-01 17:50:38 +0000360 qget = quotes.get
Fred Drake397b6152002-12-31 07:14:18 +0000361 sio = _StringIO()
Fred Drake49cc01e2001-11-01 17:50:38 +0000362 write = sio.write
Fred Drake1ef106c2001-09-04 19:43:26 +0000363 for char in object:
364 if char.isalpha():
Fred Drake49cc01e2001-11-01 17:50:38 +0000365 write(char)
Fred Drake1ef106c2001-09-04 19:43:26 +0000366 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000367 write(qget(char, repr(char)[1:-1]))
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000368 return ("%s%s%s" % (closure, sio.getvalue(), closure)), True, False
Tim Peters95b3f782001-05-14 18:39:41 +0000369
Walter Dörwald1b626ca2004-11-15 13:51:41 +0000370 r = getattr(typ, "__repr__", None)
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000371 if issubclass(typ, dict) and r is dict.__repr__:
Fred Drake49cc01e2001-11-01 17:50:38 +0000372 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000373 return "{}", True, False
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200374 objid = id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000375 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000376 return "{...}", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000377 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000378 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000379 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000380 readable = True
381 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000382 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000383 append = components.append
384 level += 1
385 saferepr = _safe_repr
Raymond Hettingera7da1662009-11-19 01:07:05 +0000386 items = sorted(object.items(), key=_safe_tuple)
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000387 for k, v in items:
Fred Drake49cc01e2001-11-01 17:50:38 +0000388 krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
389 vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
390 append("%s: %s" % (krepr, vrepr))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000391 readable = readable and kreadable and vreadable
Fred Drake49cc01e2001-11-01 17:50:38 +0000392 if krecur or vrecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000393 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000394 del context[objid]
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200395 return "{%s}" % ", ".join(components), readable, recursive
Tim Peters95b3f782001-05-14 18:39:41 +0000396
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000397 if (issubclass(typ, list) and r is list.__repr__) or \
398 (issubclass(typ, tuple) and r is tuple.__repr__):
399 if issubclass(typ, list):
Fred Drake49cc01e2001-11-01 17:50:38 +0000400 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000401 return "[]", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000402 format = "[%s]"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200403 elif len(object) == 1:
Fred Drake49cc01e2001-11-01 17:50:38 +0000404 format = "(%s,)"
405 else:
406 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000407 return "()", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000408 format = "(%s)"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200409 objid = id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000410 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000411 return format % "...", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000412 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000413 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000414 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000415 readable = True
416 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000417 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000418 append = components.append
419 level += 1
420 for o in object:
421 orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)
422 append(orepr)
423 if not oreadable:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000424 readable = False
Fred Drake49cc01e2001-11-01 17:50:38 +0000425 if orecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000426 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000427 del context[objid]
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200428 return format % ", ".join(components), readable, recursive
Tim Peters88768482001-11-13 21:51:26 +0000429
Walter Dörwald70a6b492004-02-12 17:35:32 +0000430 rep = repr(object)
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000431 return rep, (rep and not rep.startswith('<')), False
Tim Peters95b3f782001-05-14 18:39:41 +0000432
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000433
Fred Drake49cc01e2001-11-01 17:50:38 +0000434def _recursion(object):
435 return ("<Recursion on %s with id=%s>"
Antoine Pitrou7d36e2f2013-10-03 21:29:36 +0200436 % (type(object).__name__, id(object)))
Fred Drakea89fda01997-04-16 16:59:30 +0000437
Fred Drake49cc01e2001-11-01 17:50:38 +0000438
439def _perfcheck(object=None):
440 import time
441 if object is None:
442 object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
443 p = PrettyPrinter()
444 t1 = time.time()
445 _safe_repr(object, {}, None, 0)
446 t2 = time.time()
447 p.pformat(object)
448 t3 = time.time()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000449 print("_safe_repr:", t2 - t1)
450 print("pformat:", t3 - t2)
Fred Drake49cc01e2001-11-01 17:50:38 +0000451
452if __name__ == "__main__":
453 _perfcheck()