Issue #7701: Fix crash in binascii.b2a_uu() in debug mode when given a
[python.git] / Lib / pprint.py
blob910283e60913e3c209d0d9d4ed799796155bad31
1 # Author: Fred L. Drake, Jr.
2 # fdrake@acm.org
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
7 # tuples with fairly non-descriptive content. This is modeled very much
8 # after Lisp/Scheme - style pretty-printing of lists. If you find it
9 # useful, thank small children who sleep at night.
11 """Support to pretty-print lists, tuples, & dictionaries recursively.
13 Very simple, but useful, especially in debugging data structures.
15 Classes
16 -------
18 PrettyPrinter()
19 Handle pretty-printing operations onto a stream using a configured
20 set of formatting parameters.
22 Functions
23 ---------
25 pformat()
26 Format a Python object into a pretty-printed representation.
28 pprint()
29 Pretty-print a Python object to a stream [default is sys.stdout].
31 saferepr()
32 Generate a 'standard' repr()-like value, but protect against recursive
33 data structures.
35 """
37 import sys as _sys
38 import warnings
40 from cStringIO import StringIO as _StringIO
42 __all__ = ["pprint","pformat","isreadable","isrecursive","saferepr",
43 "PrettyPrinter"]
45 # cache these for faster access:
46 _commajoin = ", ".join
47 _id = id
48 _len = len
49 _type = type
52 def pprint(object, stream=None, indent=1, width=80, depth=None):
53 """Pretty-print a Python object to a stream [default is sys.stdout]."""
54 printer = PrettyPrinter(
55 stream=stream, indent=indent, width=width, depth=depth)
56 printer.pprint(object)
58 def pformat(object, indent=1, width=80, depth=None):
59 """Format a Python object into a pretty-printed representation."""
60 return PrettyPrinter(indent=indent, width=width, depth=depth).pformat(object)
62 def saferepr(object):
63 """Version of repr() which can handle recursive data structures."""
64 return _safe_repr(object, {}, None, 0)[0]
66 def isreadable(object):
67 """Determine if saferepr(object) is readable by eval()."""
68 return _safe_repr(object, {}, None, 0)[1]
70 def isrecursive(object):
71 """Determine if object requires a recursive representation."""
72 return _safe_repr(object, {}, None, 0)[2]
74 def _sorted(iterable):
75 with warnings.catch_warnings():
76 if _sys.py3kwarning:
77 warnings.filterwarnings("ignore", "comparing unequal types "
78 "not supported", DeprecationWarning)
79 return sorted(iterable)
81 class PrettyPrinter:
82 def __init__(self, indent=1, width=80, depth=None, stream=None):
83 """Handle pretty printing operations onto a stream using a set of
84 configured parameters.
86 indent
87 Number of spaces to indent for each level of nesting.
89 width
90 Attempted maximum number of columns in the output.
92 depth
93 The maximum depth to print out nested structures.
95 stream
96 The desired output stream. If omitted (or false), the standard
97 output stream available at construction will be used.
99 """
100 indent = int(indent)
101 width = int(width)
102 assert indent >= 0, "indent must be >= 0"
103 assert depth is None or depth > 0, "depth must be > 0"
104 assert width, "width must be != 0"
105 self._depth = depth
106 self._indent_per_level = indent
107 self._width = width
108 if stream is not None:
109 self._stream = stream
110 else:
111 self._stream = _sys.stdout
113 def pprint(self, object):
114 self._format(object, self._stream, 0, 0, {}, 0)
115 self._stream.write("\n")
117 def pformat(self, object):
118 sio = _StringIO()
119 self._format(object, sio, 0, 0, {}, 0)
120 return sio.getvalue()
122 def isrecursive(self, object):
123 return self.format(object, {}, 0, 0)[2]
125 def isreadable(self, object):
126 s, readable, recursive = self.format(object, {}, 0, 0)
127 return readable and not recursive
129 def _format(self, object, stream, indent, allowance, context, level):
130 level = level + 1
131 objid = _id(object)
132 if objid in context:
133 stream.write(_recursion(object))
134 self._recursive = True
135 self._readable = False
136 return
137 rep = self._repr(object, context, level - 1)
138 typ = _type(object)
139 sepLines = _len(rep) > (self._width - 1 - indent - allowance)
140 write = stream.write
142 if self._depth and level > self._depth:
143 write(rep)
144 return
146 r = getattr(typ, "__repr__", None)
147 if issubclass(typ, dict) and r is dict.__repr__:
148 write('{')
149 if self._indent_per_level > 1:
150 write((self._indent_per_level - 1) * ' ')
151 length = _len(object)
152 if length:
153 context[objid] = 1
154 indent = indent + self._indent_per_level
155 items = _sorted(object.items())
156 key, ent = items[0]
157 rep = self._repr(key, context, level)
158 write(rep)
159 write(': ')
160 self._format(ent, stream, indent + _len(rep) + 2,
161 allowance + 1, context, level)
162 if length > 1:
163 for key, ent in items[1:]:
164 rep = self._repr(key, context, level)
165 if sepLines:
166 write(',\n%s%s: ' % (' '*indent, rep))
167 else:
168 write(', %s: ' % rep)
169 self._format(ent, stream, indent + _len(rep) + 2,
170 allowance + 1, context, level)
171 indent = indent - self._indent_per_level
172 del context[objid]
173 write('}')
174 return
176 if ((issubclass(typ, list) and r is list.__repr__) or
177 (issubclass(typ, tuple) and r is tuple.__repr__) or
178 (issubclass(typ, set) and r is set.__repr__) or
179 (issubclass(typ, frozenset) and r is frozenset.__repr__)
181 length = _len(object)
182 if issubclass(typ, list):
183 write('[')
184 endchar = ']'
185 elif issubclass(typ, set):
186 if not length:
187 write('set()')
188 return
189 write('set([')
190 endchar = '])'
191 object = _sorted(object)
192 indent += 4
193 elif issubclass(typ, frozenset):
194 if not length:
195 write('frozenset()')
196 return
197 write('frozenset([')
198 endchar = '])'
199 object = _sorted(object)
200 indent += 10
201 else:
202 write('(')
203 endchar = ')'
204 if self._indent_per_level > 1 and sepLines:
205 write((self._indent_per_level - 1) * ' ')
206 if length:
207 context[objid] = 1
208 indent = indent + self._indent_per_level
209 self._format(object[0], stream, indent, allowance + 1,
210 context, level)
211 if length > 1:
212 for ent in object[1:]:
213 if sepLines:
214 write(',\n' + ' '*indent)
215 else:
216 write(', ')
217 self._format(ent, stream, indent,
218 allowance + 1, context, level)
219 indent = indent - self._indent_per_level
220 del context[objid]
221 if issubclass(typ, tuple) and length == 1:
222 write(',')
223 write(endchar)
224 return
226 write(rep)
228 def _repr(self, object, context, level):
229 repr, readable, recursive = self.format(object, context.copy(),
230 self._depth, level)
231 if not readable:
232 self._readable = False
233 if recursive:
234 self._recursive = True
235 return repr
237 def format(self, object, context, maxlevels, level):
238 """Format object for a specific context, returning a string
239 and flags indicating whether the representation is 'readable'
240 and whether the object represents a recursive construct.
242 return _safe_repr(object, context, maxlevels, level)
245 # Return triple (repr_string, isreadable, isrecursive).
247 def _safe_repr(object, context, maxlevels, level):
248 typ = _type(object)
249 if typ is str:
250 if 'locale' not in _sys.modules:
251 return repr(object), True, False
252 if "'" in object and '"' not in object:
253 closure = '"'
254 quotes = {'"': '\\"'}
255 else:
256 closure = "'"
257 quotes = {"'": "\\'"}
258 qget = quotes.get
259 sio = _StringIO()
260 write = sio.write
261 for char in object:
262 if char.isalpha():
263 write(char)
264 else:
265 write(qget(char, repr(char)[1:-1]))
266 return ("%s%s%s" % (closure, sio.getvalue(), closure)), True, False
268 r = getattr(typ, "__repr__", None)
269 if issubclass(typ, dict) and r is dict.__repr__:
270 if not object:
271 return "{}", True, False
272 objid = _id(object)
273 if maxlevels and level >= maxlevels:
274 return "{...}", False, objid in context
275 if objid in context:
276 return _recursion(object), False, True
277 context[objid] = 1
278 readable = True
279 recursive = False
280 components = []
281 append = components.append
282 level += 1
283 saferepr = _safe_repr
284 for k, v in _sorted(object.items()):
285 krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
286 vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
287 append("%s: %s" % (krepr, vrepr))
288 readable = readable and kreadable and vreadable
289 if krecur or vrecur:
290 recursive = True
291 del context[objid]
292 return "{%s}" % _commajoin(components), readable, recursive
294 if (issubclass(typ, list) and r is list.__repr__) or \
295 (issubclass(typ, tuple) and r is tuple.__repr__):
296 if issubclass(typ, list):
297 if not object:
298 return "[]", True, False
299 format = "[%s]"
300 elif _len(object) == 1:
301 format = "(%s,)"
302 else:
303 if not object:
304 return "()", True, False
305 format = "(%s)"
306 objid = _id(object)
307 if maxlevels and level >= maxlevels:
308 return format % "...", False, objid in context
309 if objid in context:
310 return _recursion(object), False, True
311 context[objid] = 1
312 readable = True
313 recursive = False
314 components = []
315 append = components.append
316 level += 1
317 for o in object:
318 orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)
319 append(orepr)
320 if not oreadable:
321 readable = False
322 if orecur:
323 recursive = True
324 del context[objid]
325 return format % _commajoin(components), readable, recursive
327 rep = repr(object)
328 return rep, (rep and not rep.startswith('<')), False
331 def _recursion(object):
332 return ("<Recursion on %s with id=%s>"
333 % (_type(object).__name__, _id(object)))
336 def _perfcheck(object=None):
337 import time
338 if object is None:
339 object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
340 p = PrettyPrinter()
341 t1 = time.time()
342 _safe_repr(object, {}, None, 0)
343 t2 = time.time()
344 p.pformat(object)
345 t3 = time.time()
346 print "_safe_repr:", t2 - t1
347 print "pformat:", t3 - t2
349 if __name__ == "__main__":
350 _perfcheck()