Catch situations where currentframe() returns None. See SF patch #1447410, this is...
[python.git] / Lib / pprint.py
blobf77a0e224832fb012a37c2011533e0eee61f77f1
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 sepLines:
135 r = getattr(typ, "__repr__", None)
136 if issubclass(typ, dict) and r is dict.__repr__:
137 write('{')
138 if self._indent_per_level > 1:
139 write((self._indent_per_level - 1) * ' ')
140 length = _len(object)
141 if length:
142 context[objid] = 1
143 indent = indent + self._indent_per_level
144 items = object.items()
145 items.sort()
146 key, ent = items[0]
147 rep = self._repr(key, context, level)
148 write(rep)
149 write(': ')
150 self._format(ent, stream, indent + _len(rep) + 2,
151 allowance + 1, context, level)
152 if length > 1:
153 for key, ent in items[1:]:
154 rep = self._repr(key, context, level)
155 write(',\n%s%s: ' % (' '*indent, rep))
156 self._format(ent, stream, indent + _len(rep) + 2,
157 allowance + 1, context, level)
158 indent = indent - self._indent_per_level
159 del context[objid]
160 write('}')
161 return
163 if (issubclass(typ, list) and r is list.__repr__) or \
164 (issubclass(typ, tuple) and r is tuple.__repr__):
165 if issubclass(typ, list):
166 write('[')
167 endchar = ']'
168 else:
169 write('(')
170 endchar = ')'
171 if self._indent_per_level > 1:
172 write((self._indent_per_level - 1) * ' ')
173 length = _len(object)
174 if length:
175 context[objid] = 1
176 indent = indent + self._indent_per_level
177 self._format(object[0], stream, indent, allowance + 1,
178 context, level)
179 if length > 1:
180 for ent in object[1:]:
181 write(',\n' + ' '*indent)
182 self._format(ent, stream, indent,
183 allowance + 1, context, level)
184 indent = indent - self._indent_per_level
185 del context[objid]
186 if issubclass(typ, tuple) and length == 1:
187 write(',')
188 write(endchar)
189 return
191 write(rep)
193 def _repr(self, object, context, level):
194 repr, readable, recursive = self.format(object, context.copy(),
195 self._depth, level)
196 if not readable:
197 self._readable = False
198 if recursive:
199 self._recursive = True
200 return repr
202 def format(self, object, context, maxlevels, level):
203 """Format object for a specific context, returning a string
204 and flags indicating whether the representation is 'readable'
205 and whether the object represents a recursive construct.
207 return _safe_repr(object, context, maxlevels, level)
210 # Return triple (repr_string, isreadable, isrecursive).
212 def _safe_repr(object, context, maxlevels, level):
213 typ = _type(object)
214 if typ is str:
215 if 'locale' not in _sys.modules:
216 return repr(object), True, False
217 if "'" in object and '"' not in object:
218 closure = '"'
219 quotes = {'"': '\\"'}
220 else:
221 closure = "'"
222 quotes = {"'": "\\'"}
223 qget = quotes.get
224 sio = _StringIO()
225 write = sio.write
226 for char in object:
227 if char.isalpha():
228 write(char)
229 else:
230 write(qget(char, repr(char)[1:-1]))
231 return ("%s%s%s" % (closure, sio.getvalue(), closure)), True, False
233 r = getattr(typ, "__repr__", None)
234 if issubclass(typ, dict) and r is dict.__repr__:
235 if not object:
236 return "{}", True, False
237 objid = _id(object)
238 if maxlevels and level > maxlevels:
239 return "{...}", False, objid in context
240 if objid in context:
241 return _recursion(object), False, True
242 context[objid] = 1
243 readable = True
244 recursive = False
245 components = []
246 append = components.append
247 level += 1
248 saferepr = _safe_repr
249 for k, v in object.iteritems():
250 krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
251 vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
252 append("%s: %s" % (krepr, vrepr))
253 readable = readable and kreadable and vreadable
254 if krecur or vrecur:
255 recursive = True
256 del context[objid]
257 return "{%s}" % _commajoin(components), readable, recursive
259 if (issubclass(typ, list) and r is list.__repr__) or \
260 (issubclass(typ, tuple) and r is tuple.__repr__):
261 if issubclass(typ, list):
262 if not object:
263 return "[]", True, False
264 format = "[%s]"
265 elif _len(object) == 1:
266 format = "(%s,)"
267 else:
268 if not object:
269 return "()", True, False
270 format = "(%s)"
271 objid = _id(object)
272 if maxlevels and level > maxlevels:
273 return format % "...", False, objid in context
274 if objid in context:
275 return _recursion(object), False, True
276 context[objid] = 1
277 readable = True
278 recursive = False
279 components = []
280 append = components.append
281 level += 1
282 for o in object:
283 orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)
284 append(orepr)
285 if not oreadable:
286 readable = False
287 if orecur:
288 recursive = True
289 del context[objid]
290 return format % _commajoin(components), readable, recursive
292 rep = repr(object)
293 return rep, (rep and not rep.startswith('<')), False
296 def _recursion(object):
297 return ("<Recursion on %s with id=%s>"
298 % (_type(object).__name__, _id(object)))
301 def _perfcheck(object=None):
302 import time
303 if object is None:
304 object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
305 p = PrettyPrinter()
306 t1 = time.time()
307 _safe_repr(object, {}, None, 0)
308 t2 = time.time()
309 p.pformat(object)
310 t3 = time.time()
311 print "_safe_repr:", t2 - t1
312 print "pformat:", t3 - t2
314 if __name__ == "__main__":
315 _perfcheck()