blob: 330099dfea61f05c824bc1a6fdfc194ac0a44541 [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
Fred Drake397b6152002-12-31 07:14:18 +000037import sys as _sys
Antoine Pitroub9d49632010-01-04 23:22:44 +000038import warnings
Guido van Rossum5e92aff1997-04-16 00:49:59 +000039
doko@ubuntu.com6cb43432013-04-08 21:20:09 +020040try:
41 from cStringIO import StringIO as _StringIO
42except ImportError:
43 from StringIO import StringIO as _StringIO
Guido van Rossum5e92aff1997-04-16 00:49:59 +000044
Skip Montanaroc62c81e2001-02-12 02:00:42 +000045__all__ = ["pprint","pformat","isreadable","isrecursive","saferepr",
46 "PrettyPrinter"]
Guido van Rossum5e92aff1997-04-16 00:49:59 +000047
Fred Drake49cc01e2001-11-01 17:50:38 +000048# cache these for faster access:
49_commajoin = ", ".join
Fred Drake49cc01e2001-11-01 17:50:38 +000050_id = id
51_len = len
52_type = type
53
54
Walter Dörwaldc8de4582003-12-03 20:26:05 +000055def pprint(object, stream=None, indent=1, width=80, depth=None):
Skip Montanaro2dc0c132004-05-14 16:31:56 +000056 """Pretty-print a Python object to a stream [default is sys.stdout]."""
Walter Dörwaldc8de4582003-12-03 20:26:05 +000057 printer = PrettyPrinter(
58 stream=stream, indent=indent, width=width, depth=depth)
Fred Drakea89fda01997-04-16 16:59:30 +000059 printer.pprint(object)
Guido van Rossum5e92aff1997-04-16 00:49:59 +000060
Walter Dörwaldc8de4582003-12-03 20:26:05 +000061def pformat(object, indent=1, width=80, depth=None):
Fred Drakea89fda01997-04-16 16:59:30 +000062 """Format a Python object into a pretty-printed representation."""
Walter Dörwaldc8de4582003-12-03 20:26:05 +000063 return PrettyPrinter(indent=indent, width=width, depth=depth).pformat(object)
Guido van Rossum5e92aff1997-04-16 00:49:59 +000064
Fred Drakea89fda01997-04-16 16:59:30 +000065def saferepr(object):
66 """Version of repr() which can handle recursive data structures."""
Fred Drake49cc01e2001-11-01 17:50:38 +000067 return _safe_repr(object, {}, None, 0)[0]
Guido van Rossum5e92aff1997-04-16 00:49:59 +000068
Tim Petersa814db52001-05-14 07:05:58 +000069def isreadable(object):
70 """Determine if saferepr(object) is readable by eval()."""
Fred Drake49cc01e2001-11-01 17:50:38 +000071 return _safe_repr(object, {}, None, 0)[1]
Tim Petersa814db52001-05-14 07:05:58 +000072
73def isrecursive(object):
74 """Determine if object requires a recursive representation."""
Fred Drake49cc01e2001-11-01 17:50:38 +000075 return _safe_repr(object, {}, None, 0)[2]
Guido van Rossum5e92aff1997-04-16 00:49:59 +000076
Antoine Pitroub9d49632010-01-04 23:22:44 +000077def _sorted(iterable):
78 with warnings.catch_warnings():
79 if _sys.py3kwarning:
80 warnings.filterwarnings("ignore", "comparing unequal types "
81 "not supported", DeprecationWarning)
82 return sorted(iterable)
83
Fred Drakea89fda01997-04-16 16:59:30 +000084class PrettyPrinter:
85 def __init__(self, indent=1, width=80, depth=None, stream=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000086 """Handle pretty printing operations onto a stream using a set of
87 configured parameters.
Guido van Rossum5e92aff1997-04-16 00:49:59 +000088
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000089 indent
90 Number of spaces to indent for each level of nesting.
Guido van Rossum5e92aff1997-04-16 00:49:59 +000091
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000092 width
93 Attempted maximum number of columns in the output.
Guido van Rossum5e92aff1997-04-16 00:49:59 +000094
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000095 depth
96 The maximum depth to print out nested structures.
Guido van Rossum5e92aff1997-04-16 00:49:59 +000097
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000098 stream
99 The desired output stream. If omitted (or false), the standard
100 output stream available at construction will be used.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000101
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000102 """
103 indent = int(indent)
104 width = int(width)
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000105 assert indent >= 0, "indent must be >= 0"
Tim Petersa814db52001-05-14 07:05:58 +0000106 assert depth is None or depth > 0, "depth must be > 0"
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000107 assert width, "width must be != 0"
Fred Drakee6691ef2002-07-08 12:28:06 +0000108 self._depth = depth
109 self._indent_per_level = indent
110 self._width = width
Raymond Hettinger16e3c422002-06-01 16:07:16 +0000111 if stream is not None:
Fred Drakee6691ef2002-07-08 12:28:06 +0000112 self._stream = stream
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000113 else:
Fred Drake397b6152002-12-31 07:14:18 +0000114 self._stream = _sys.stdout
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000115
Fred Drakea89fda01997-04-16 16:59:30 +0000116 def pprint(self, object):
Walter Dörwalde62e9362005-11-11 18:18:51 +0000117 self._format(object, self._stream, 0, 0, {}, 0)
118 self._stream.write("\n")
Fred Drakea89fda01997-04-16 16:59:30 +0000119
120 def pformat(self, object):
Fred Drake397b6152002-12-31 07:14:18 +0000121 sio = _StringIO()
Fred Drakee6691ef2002-07-08 12:28:06 +0000122 self._format(object, sio, 0, 0, {}, 0)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000123 return sio.getvalue()
Fred Drakea89fda01997-04-16 16:59:30 +0000124
Fred Drakee0ffabe1997-07-18 20:42:39 +0000125 def isrecursive(self, object):
Fred Drake397b6152002-12-31 07:14:18 +0000126 return self.format(object, {}, 0, 0)[2]
Fred Drakee0ffabe1997-07-18 20:42:39 +0000127
128 def isreadable(self, object):
Fred Drake397b6152002-12-31 07:14:18 +0000129 s, readable, recursive = self.format(object, {}, 0, 0)
Fred Drakeaee113d2002-04-02 05:08:35 +0000130 return readable and not recursive
Fred Drakee0ffabe1997-07-18 20:42:39 +0000131
Fred Drakee6691ef2002-07-08 12:28:06 +0000132 def _format(self, object, stream, indent, allowance, context, level):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000133 level = level + 1
Fred Drake49cc01e2001-11-01 17:50:38 +0000134 objid = _id(object)
135 if objid in context:
136 stream.write(_recursion(object))
Fred Drakee6691ef2002-07-08 12:28:06 +0000137 self._recursive = True
138 self._readable = False
Fred Drake49cc01e2001-11-01 17:50:38 +0000139 return
Fred Drakee6691ef2002-07-08 12:28:06 +0000140 rep = self._repr(object, context, level - 1)
Fred Drake49cc01e2001-11-01 17:50:38 +0000141 typ = _type(object)
Fred Drakee6691ef2002-07-08 12:28:06 +0000142 sepLines = _len(rep) > (self._width - 1 - indent - allowance)
Fred Drake49cc01e2001-11-01 17:50:38 +0000143 write = stream.write
Fred Drakea89fda01997-04-16 16:59:30 +0000144
Georg Brandl23da6e62008-05-12 16:26:52 +0000145 if self._depth and level > self._depth:
146 write(rep)
147 return
148
Georg Brandldcd6b522008-01-20 11:13:29 +0000149 r = getattr(typ, "__repr__", None)
150 if issubclass(typ, dict) and r is dict.__repr__:
151 write('{')
152 if self._indent_per_level > 1:
153 write((self._indent_per_level - 1) * ' ')
154 length = _len(object)
155 if length:
156 context[objid] = 1
157 indent = indent + self._indent_per_level
Antoine Pitroub9d49632010-01-04 23:22:44 +0000158 items = _sorted(object.items())
Georg Brandldcd6b522008-01-20 11:13:29 +0000159 key, ent = items[0]
160 rep = self._repr(key, context, level)
161 write(rep)
162 write(': ')
163 self._format(ent, stream, indent + _len(rep) + 2,
164 allowance + 1, context, level)
165 if length > 1:
166 for key, ent in items[1:]:
167 rep = self._repr(key, context, level)
168 if sepLines:
Barry Warsaw00859c02001-11-28 05:49:39 +0000169 write(',\n%s%s: ' % (' '*indent, rep))
Georg Brandldcd6b522008-01-20 11:13:29 +0000170 else:
171 write(', %s: ' % rep)
172 self._format(ent, stream, indent + _len(rep) + 2,
173 allowance + 1, context, level)
174 indent = indent - self._indent_per_level
175 del context[objid]
176 write('}')
177 return
Fred Drakea89fda01997-04-16 16:59:30 +0000178
Raymond Hettingerc226c312008-01-23 00:04:40 +0000179 if ((issubclass(typ, list) and r is list.__repr__) or
180 (issubclass(typ, tuple) and r is tuple.__repr__) or
181 (issubclass(typ, set) and r is set.__repr__) or
182 (issubclass(typ, frozenset) and r is frozenset.__repr__)
183 ):
Raymond Hettinger5310b692008-01-24 21:47:56 +0000184 length = _len(object)
Georg Brandldcd6b522008-01-20 11:13:29 +0000185 if issubclass(typ, list):
186 write('[')
187 endchar = ']'
Raymond Hettingerc226c312008-01-23 00:04:40 +0000188 elif issubclass(typ, set):
Raymond Hettinger5310b692008-01-24 21:47:56 +0000189 if not length:
190 write('set()')
191 return
Raymond Hettingerc226c312008-01-23 00:04:40 +0000192 write('set([')
193 endchar = '])'
Antoine Pitroub9d49632010-01-04 23:22:44 +0000194 object = _sorted(object)
Raymond Hettingerc226c312008-01-23 00:04:40 +0000195 indent += 4
196 elif issubclass(typ, frozenset):
Raymond Hettinger5310b692008-01-24 21:47:56 +0000197 if not length:
198 write('frozenset()')
199 return
Raymond Hettingerc226c312008-01-23 00:04:40 +0000200 write('frozenset([')
201 endchar = '])'
Antoine Pitroub9d49632010-01-04 23:22:44 +0000202 object = _sorted(object)
Raymond Hettinger5310b692008-01-24 21:47:56 +0000203 indent += 10
Georg Brandldcd6b522008-01-20 11:13:29 +0000204 else:
205 write('(')
206 endchar = ')'
Facundo Batista2da91c32008-06-21 17:43:56 +0000207 if self._indent_per_level > 1 and sepLines:
Georg Brandldcd6b522008-01-20 11:13:29 +0000208 write((self._indent_per_level - 1) * ' ')
Georg Brandldcd6b522008-01-20 11:13:29 +0000209 if length:
210 context[objid] = 1
211 indent = indent + self._indent_per_level
212 self._format(object[0], stream, indent, allowance + 1,
213 context, level)
214 if length > 1:
215 for ent in object[1:]:
216 if sepLines:
Fred Drake49cc01e2001-11-01 17:50:38 +0000217 write(',\n' + ' '*indent)
Georg Brandldcd6b522008-01-20 11:13:29 +0000218 else:
219 write(', ')
220 self._format(ent, stream, indent,
221 allowance + 1, context, level)
222 indent = indent - self._indent_per_level
223 del context[objid]
224 if issubclass(typ, tuple) and length == 1:
225 write(',')
226 write(endchar)
227 return
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000228
Georg Brandl23da6e62008-05-12 16:26:52 +0000229 write(rep)
Georg Brandldcd6b522008-01-20 11:13:29 +0000230
Fred Drakee6691ef2002-07-08 12:28:06 +0000231 def _repr(self, object, context, level):
Fred Drakeaee113d2002-04-02 05:08:35 +0000232 repr, readable, recursive = self.format(object, context.copy(),
Fred Drakee6691ef2002-07-08 12:28:06 +0000233 self._depth, level)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000234 if not readable:
Fred Drakee6691ef2002-07-08 12:28:06 +0000235 self._readable = False
Tim Petersa814db52001-05-14 07:05:58 +0000236 if recursive:
Fred Drakee6691ef2002-07-08 12:28:06 +0000237 self._recursive = True
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000238 return repr
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000239
Fred Drakeaee113d2002-04-02 05:08:35 +0000240 def format(self, object, context, maxlevels, level):
241 """Format object for a specific context, returning a string
242 and flags indicating whether the representation is 'readable'
243 and whether the object represents a recursive construct.
244 """
245 return _safe_repr(object, context, maxlevels, level)
246
247
Tim Petersa814db52001-05-14 07:05:58 +0000248# Return triple (repr_string, isreadable, isrecursive).
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000249
Fred Drake49cc01e2001-11-01 17:50:38 +0000250def _safe_repr(object, context, maxlevels, level):
251 typ = _type(object)
Martin v. Löwisd02879d2003-06-07 20:47:37 +0000252 if typ is str:
Fred Drake397b6152002-12-31 07:14:18 +0000253 if 'locale' not in _sys.modules:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000254 return repr(object), True, False
Fred Drake1ef106c2001-09-04 19:43:26 +0000255 if "'" in object and '"' not in object:
256 closure = '"'
257 quotes = {'"': '\\"'}
258 else:
259 closure = "'"
260 quotes = {"'": "\\'"}
Fred Drake49cc01e2001-11-01 17:50:38 +0000261 qget = quotes.get
Fred Drake397b6152002-12-31 07:14:18 +0000262 sio = _StringIO()
Fred Drake49cc01e2001-11-01 17:50:38 +0000263 write = sio.write
Fred Drake1ef106c2001-09-04 19:43:26 +0000264 for char in object:
265 if char.isalpha():
Fred Drake49cc01e2001-11-01 17:50:38 +0000266 write(char)
Fred Drake1ef106c2001-09-04 19:43:26 +0000267 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000268 write(qget(char, repr(char)[1:-1]))
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000269 return ("%s%s%s" % (closure, sio.getvalue(), closure)), True, False
Tim Peters95b3f782001-05-14 18:39:41 +0000270
Walter Dörwald1b626ca2004-11-15 13:51:41 +0000271 r = getattr(typ, "__repr__", None)
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000272 if issubclass(typ, dict) and r is dict.__repr__:
Fred Drake49cc01e2001-11-01 17:50:38 +0000273 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000274 return "{}", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000275 objid = _id(object)
Georg Brandl23da6e62008-05-12 16:26:52 +0000276 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000277 return "{...}", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000278 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000279 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000280 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000281 readable = True
282 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000283 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000284 append = components.append
285 level += 1
286 saferepr = _safe_repr
Antoine Pitroub9d49632010-01-04 23:22:44 +0000287 for k, v in _sorted(object.items()):
Fred Drake49cc01e2001-11-01 17:50:38 +0000288 krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
289 vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
290 append("%s: %s" % (krepr, vrepr))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000291 readable = readable and kreadable and vreadable
Fred Drake49cc01e2001-11-01 17:50:38 +0000292 if krecur or vrecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000293 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000294 del context[objid]
295 return "{%s}" % _commajoin(components), readable, recursive
Tim Peters95b3f782001-05-14 18:39:41 +0000296
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000297 if (issubclass(typ, list) and r is list.__repr__) or \
298 (issubclass(typ, tuple) and r is tuple.__repr__):
299 if issubclass(typ, list):
Fred Drake49cc01e2001-11-01 17:50:38 +0000300 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000301 return "[]", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000302 format = "[%s]"
303 elif _len(object) == 1:
304 format = "(%s,)"
305 else:
306 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000307 return "()", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000308 format = "(%s)"
309 objid = _id(object)
Georg Brandl23da6e62008-05-12 16:26:52 +0000310 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000311 return format % "...", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000312 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000313 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000314 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000315 readable = True
316 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000317 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000318 append = components.append
319 level += 1
320 for o in object:
321 orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)
322 append(orepr)
323 if not oreadable:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000324 readable = False
Fred Drake49cc01e2001-11-01 17:50:38 +0000325 if orecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000326 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000327 del context[objid]
328 return format % _commajoin(components), readable, recursive
Tim Peters88768482001-11-13 21:51:26 +0000329
Walter Dörwald70a6b492004-02-12 17:35:32 +0000330 rep = repr(object)
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000331 return rep, (rep and not rep.startswith('<')), False
Tim Peters95b3f782001-05-14 18:39:41 +0000332
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000333
Fred Drake49cc01e2001-11-01 17:50:38 +0000334def _recursion(object):
335 return ("<Recursion on %s with id=%s>"
336 % (_type(object).__name__, _id(object)))
Fred Drakea89fda01997-04-16 16:59:30 +0000337
Fred Drake49cc01e2001-11-01 17:50:38 +0000338
339def _perfcheck(object=None):
340 import time
341 if object is None:
342 object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
343 p = PrettyPrinter()
344 t1 = time.time()
345 _safe_repr(object, {}, None, 0)
346 t2 = time.time()
347 p.pformat(object)
348 t3 = time.time()
349 print "_safe_repr:", t2 - t1
350 print "pformat:", t3 - t2
351
352if __name__ == "__main__":
353 _perfcheck()