Fix HAVE_DECL_ISINF/ISNAN test (again).
[python.git] / Lib / pprint.py
blobc48465b8d5855304de91697ef9065e4843bcdfa3
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
39 from cStringIO import StringIO as _StringIO
41 __all__ = ["pprint","pformat","isreadable","isrecursive","saferepr",
42 "PrettyPrinter"]
44 # cache these for faster access:
45 _commajoin = ", ".join
46 _id = id
47 _len = len
48 _type = type
51 def pprint(object, stream=None, indent=1, width=80, depth=None):
52 """Pretty-print a Python object to a stream [default is sys.stdout]."""
53 printer = PrettyPrinter(
54 stream=stream, indent=indent, width=width, depth=depth)
55 printer.pprint(object)
57 def pformat(object, indent=1, width=80, depth=None):
58 """Format a Python object into a pretty-printed representation."""
59 return PrettyPrinter(indent=indent, width=width, depth=depth).pformat(object)
61 def saferepr(object):
62 """Version of repr() which can handle recursive data structures."""
63 return _safe_repr(object, {}, None, 0)[0]
65 def isreadable(object):
66 """Determine if saferepr(object) is readable by eval()."""
67 return _safe_repr(object, {}, None, 0)[1]
69 def isrecursive(object):
70 """Determine if object requires a recursive representation."""
71 return _safe_repr(object, {}, None, 0)[2]
73 class PrettyPrinter:
74 def __init__(self, indent=1, width=80, depth=None, stream=None):
75 """Handle pretty printing operations onto a stream using a set of
76 configured parameters.
78 indent
79 Number of spaces to indent for each level of nesting.
81 width
82 Attempted maximum number of columns in the output.
84 depth
85 The maximum depth to print out nested structures.
87 stream
88 The desired output stream. If omitted (or false), the standard
89 output stream available at construction will be used.
91 """
92 indent = int(indent)
93 width = int(width)
94 assert indent >= 0, "indent must be >= 0"
95 assert depth is None or depth > 0, "depth must be > 0"
96 assert width, "width must be != 0"
97 self._depth = depth
98 self._indent_per_level = indent
99 self._width = width
100 if stream is not None:
101 self._stream = stream
102 else:
103 self._stream = _sys.stdout
105 def pprint(self, object):
106 self._format(object, self._stream, 0, 0, {}, 0)
107 self._stream.write("\n")
109 def pformat(self, object):
110 sio = _StringIO()
111 self._format(object, sio, 0, 0, {}, 0)
112 return sio.getvalue()
114 def isrecursive(self, object):
115 return self.format(object, {}, 0, 0)[2]
117 def isreadable(self, object):
118 s, readable, recursive = self.format(object, {}, 0, 0)
119 return readable and not recursive
121 def _format(self, object, stream, indent, allowance, context, level):
122 level = level + 1
123 objid = _id(object)
124 if objid in context:
125 stream.write(_recursion(object))
126 self._recursive = True
127 self._readable = False
128 return
129 rep = self._repr(object, context, level - 1)
130 typ = _type(object)
131 sepLines = _len(rep) > (self._width - 1 - indent - allowance)
132 write = stream.write
134 if self._depth and level > self._depth:
135 write(rep)
136 return
138 r = getattr(typ, "__repr__", None)
139 if issubclass(typ, dict) and r is dict.__repr__:
140 write('{')
141 if self._indent_per_level > 1:
142 write((self._indent_per_level - 1) * ' ')
143 length = _len(object)
144 if length:
145 context[objid] = 1
146 indent = indent + self._indent_per_level
147 items = object.items()
148 items.sort()
149 key, ent = items[0]
150 rep = self._repr(key, context, level)
151 write(rep)
152 write(': ')
153 self._format(ent, stream, indent + _len(rep) + 2,
154 allowance + 1, context, level)
155 if length > 1:
156 for key, ent in items[1:]:
157 rep = self._repr(key, context, level)
158 if sepLines:
159 write(',\n%s%s: ' % (' '*indent, rep))
160 else:
161 write(', %s: ' % rep)
162 self._format(ent, stream, indent + _len(rep) + 2,
163 allowance + 1, context, level)
164 indent = indent - self._indent_per_level
165 del context[objid]
166 write('}')
167 return
169 if ((issubclass(typ, list) and r is list.__repr__) or
170 (issubclass(typ, tuple) and r is tuple.__repr__) or
171 (issubclass(typ, set) and r is set.__repr__) or
172 (issubclass(typ, frozenset) and r is frozenset.__repr__)
174 length = _len(object)
175 if issubclass(typ, list):
176 write('[')
177 endchar = ']'
178 elif issubclass(typ, set):
179 if not length:
180 write('set()')
181 return
182 write('set([')
183 endchar = '])'
184 object = sorted(object)
185 indent += 4
186 elif issubclass(typ, frozenset):
187 if not length:
188 write('frozenset()')
189 return
190 write('frozenset([')
191 endchar = '])'
192 object = sorted(object)
193 indent += 10
194 else:
195 write('(')
196 endchar = ')'
197 if self._indent_per_level > 1 and sepLines:
198 write((self._indent_per_level - 1) * ' ')
199 if length:
200 context[objid] = 1
201 indent = indent + self._indent_per_level
202 self._format(object[0], stream, indent, allowance + 1,
203 context, level)
204 if length > 1:
205 for ent in object[1:]:
206 if sepLines:
207 write(',\n' + ' '*indent)
208 else:
209 write(', ')
210 self._format(ent, stream, indent,
211 allowance + 1, context, level)
212 indent = indent - self._indent_per_level
213 del context[objid]
214 if issubclass(typ, tuple) and length == 1:
215 write(',')
216 write(endchar)
217 return
219 write(rep)
221 def _repr(self, object, context, level):
222 repr, readable, recursive = self.format(object, context.copy(),
223 self._depth, level)
224 if not readable:
225 self._readable = False
226 if recursive:
227 self._recursive = True
228 return repr
230 def format(self, object, context, maxlevels, level):
231 """Format object for a specific context, returning a string
232 and flags indicating whether the representation is 'readable'
233 and whether the object represents a recursive construct.
235 return _safe_repr(object, context, maxlevels, level)
238 # Return triple (repr_string, isreadable, isrecursive).
240 def _safe_repr(object, context, maxlevels, level):
241 typ = _type(object)
242 if typ is str:
243 if 'locale' not in _sys.modules:
244 return repr(object), True, False
245 if "'" in object and '"' not in object:
246 closure = '"'
247 quotes = {'"': '\\"'}
248 else:
249 closure = "'"
250 quotes = {"'": "\\'"}
251 qget = quotes.get
252 sio = _StringIO()
253 write = sio.write
254 for char in object:
255 if char.isalpha():
256 write(char)
257 else:
258 write(qget(char, repr(char)[1:-1]))
259 return ("%s%s%s" % (closure, sio.getvalue(), closure)), True, False
261 r = getattr(typ, "__repr__", None)
262 if issubclass(typ, dict) and r is dict.__repr__:
263 if not object:
264 return "{}", True, False
265 objid = _id(object)
266 if maxlevels and level >= maxlevels:
267 return "{...}", False, objid in context
268 if objid in context:
269 return _recursion(object), False, True
270 context[objid] = 1
271 readable = True
272 recursive = False
273 components = []
274 append = components.append
275 level += 1
276 saferepr = _safe_repr
277 for k, v in sorted(object.items()):
278 krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
279 vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
280 append("%s: %s" % (krepr, vrepr))
281 readable = readable and kreadable and vreadable
282 if krecur or vrecur:
283 recursive = True
284 del context[objid]
285 return "{%s}" % _commajoin(components), readable, recursive
287 if (issubclass(typ, list) and r is list.__repr__) or \
288 (issubclass(typ, tuple) and r is tuple.__repr__):
289 if issubclass(typ, list):
290 if not object:
291 return "[]", True, False
292 format = "[%s]"
293 elif _len(object) == 1:
294 format = "(%s,)"
295 else:
296 if not object:
297 return "()", True, False
298 format = "(%s)"
299 objid = _id(object)
300 if maxlevels and level >= maxlevels:
301 return format % "...", False, objid in context
302 if objid in context:
303 return _recursion(object), False, True
304 context[objid] = 1
305 readable = True
306 recursive = False
307 components = []
308 append = components.append
309 level += 1
310 for o in object:
311 orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)
312 append(orepr)
313 if not oreadable:
314 readable = False
315 if orecur:
316 recursive = True
317 del context[objid]
318 return format % _commajoin(components), readable, recursive
320 rep = repr(object)
321 return rep, (rep and not rep.startswith('<')), False
324 def _recursion(object):
325 return ("<Recursion on %s with id=%s>"
326 % (_type(object).__name__, _id(object)))
329 def _perfcheck(object=None):
330 import time
331 if object is None:
332 object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
333 p = PrettyPrinter()
334 t1 = time.time()
335 _safe_repr(object, {}, None, 0)
336 t2 = time.time()
337 p.pformat(object)
338 t3 = time.time()
339 print "_safe_repr:", t2 - t1
340 print "pformat:", t3 - t2
342 if __name__ == "__main__":
343 _perfcheck()