source: python/vendor/Python-2.7.6/Lib/pprint.py

Last change on this file was 388, checked in by dmik, 11 years ago

python: Update vendor to 2.7.6.

  • Property svn:eol-style set to native
File size: 11.5 KB
Line 
1# Author: Fred L. Drake, Jr.
2# fdrake@acm.org
3#
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.
10
11"""Support to pretty-print lists, tuples, & dictionaries recursively.
12
13Very simple, but useful, especially in debugging data structures.
14
15Classes
16-------
17
18PrettyPrinter()
19 Handle pretty-printing operations onto a stream using a configured
20 set of formatting parameters.
21
22Functions
23---------
24
25pformat()
26 Format a Python object into a pretty-printed representation.
27
28pprint()
29 Pretty-print a Python object to a stream [default is sys.stdout].
30
31saferepr()
32 Generate a 'standard' repr()-like value, but protect against recursive
33 data structures.
34
35"""
36
37import sys as _sys
38import warnings
39
40try:
41 from cStringIO import StringIO as _StringIO
42except ImportError:
43 from StringIO import StringIO as _StringIO
44
45__all__ = ["pprint","pformat","isreadable","isrecursive","saferepr",
46 "PrettyPrinter"]
47
48# cache these for faster access:
49_commajoin = ", ".join
50_id = id
51_len = len
52_type = type
53
54
55def pprint(object, stream=None, indent=1, width=80, depth=None):
56 """Pretty-print a Python object to a stream [default is sys.stdout]."""
57 printer = PrettyPrinter(
58 stream=stream, indent=indent, width=width, depth=depth)
59 printer.pprint(object)
60
61def pformat(object, indent=1, width=80, depth=None):
62 """Format a Python object into a pretty-printed representation."""
63 return PrettyPrinter(indent=indent, width=width, depth=depth).pformat(object)
64
65def saferepr(object):
66 """Version of repr() which can handle recursive data structures."""
67 return _safe_repr(object, {}, None, 0)[0]
68
69def isreadable(object):
70 """Determine if saferepr(object) is readable by eval()."""
71 return _safe_repr(object, {}, None, 0)[1]
72
73def isrecursive(object):
74 """Determine if object requires a recursive representation."""
75 return _safe_repr(object, {}, None, 0)[2]
76
77def _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
84class PrettyPrinter:
85 def __init__(self, indent=1, width=80, depth=None, stream=None):
86 """Handle pretty printing operations onto a stream using a set of
87 configured parameters.
88
89 indent
90 Number of spaces to indent for each level of nesting.
91
92 width
93 Attempted maximum number of columns in the output.
94
95 depth
96 The maximum depth to print out nested structures.
97
98 stream
99 The desired output stream. If omitted (or false), the standard
100 output stream available at construction will be used.
101
102 """
103 indent = int(indent)
104 width = int(width)
105 assert indent >= 0, "indent must be >= 0"
106 assert depth is None or depth > 0, "depth must be > 0"
107 assert width, "width must be != 0"
108 self._depth = depth
109 self._indent_per_level = indent
110 self._width = width
111 if stream is not None:
112 self._stream = stream
113 else:
114 self._stream = _sys.stdout
115
116 def pprint(self, object):
117 self._format(object, self._stream, 0, 0, {}, 0)
118 self._stream.write("\n")
119
120 def pformat(self, object):
121 sio = _StringIO()
122 self._format(object, sio, 0, 0, {}, 0)
123 return sio.getvalue()
124
125 def isrecursive(self, object):
126 return self.format(object, {}, 0, 0)[2]
127
128 def isreadable(self, object):
129 s, readable, recursive = self.format(object, {}, 0, 0)
130 return readable and not recursive
131
132 def _format(self, object, stream, indent, allowance, context, level):
133 level = level + 1
134 objid = _id(object)
135 if objid in context:
136 stream.write(_recursion(object))
137 self._recursive = True
138 self._readable = False
139 return
140 rep = self._repr(object, context, level - 1)
141 typ = _type(object)
142 sepLines = _len(rep) > (self._width - 1 - indent - allowance)
143 write = stream.write
144
145 if self._depth and level > self._depth:
146 write(rep)
147 return
148
149 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
158 items = _sorted(object.items())
159 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:
169 write(',\n%s%s: ' % (' '*indent, rep))
170 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
178
179 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 ):
184 length = _len(object)
185 if issubclass(typ, list):
186 write('[')
187 endchar = ']'
188 elif issubclass(typ, tuple):
189 write('(')
190 endchar = ')'
191 else:
192 if not length:
193 write(rep)
194 return
195 write(typ.__name__)
196 write('([')
197 endchar = '])'
198 indent += len(typ.__name__) + 1
199 object = _sorted(object)
200 if self._indent_per_level > 1 and sepLines:
201 write((self._indent_per_level - 1) * ' ')
202 if length:
203 context[objid] = 1
204 indent = indent + self._indent_per_level
205 self._format(object[0], stream, indent, allowance + 1,
206 context, level)
207 if length > 1:
208 for ent in object[1:]:
209 if sepLines:
210 write(',\n' + ' '*indent)
211 else:
212 write(', ')
213 self._format(ent, stream, indent,
214 allowance + 1, context, level)
215 indent = indent - self._indent_per_level
216 del context[objid]
217 if issubclass(typ, tuple) and length == 1:
218 write(',')
219 write(endchar)
220 return
221
222 write(rep)
223
224 def _repr(self, object, context, level):
225 repr, readable, recursive = self.format(object, context.copy(),
226 self._depth, level)
227 if not readable:
228 self._readable = False
229 if recursive:
230 self._recursive = True
231 return repr
232
233 def format(self, object, context, maxlevels, level):
234 """Format object for a specific context, returning a string
235 and flags indicating whether the representation is 'readable'
236 and whether the object represents a recursive construct.
237 """
238 return _safe_repr(object, context, maxlevels, level)
239
240
241# Return triple (repr_string, isreadable, isrecursive).
242
243def _safe_repr(object, context, maxlevels, level):
244 typ = _type(object)
245 if typ is str:
246 if 'locale' not in _sys.modules:
247 return repr(object), True, False
248 if "'" in object and '"' not in object:
249 closure = '"'
250 quotes = {'"': '\\"'}
251 else:
252 closure = "'"
253 quotes = {"'": "\\'"}
254 qget = quotes.get
255 sio = _StringIO()
256 write = sio.write
257 for char in object:
258 if char.isalpha():
259 write(char)
260 else:
261 write(qget(char, repr(char)[1:-1]))
262 return ("%s%s%s" % (closure, sio.getvalue(), closure)), True, False
263
264 r = getattr(typ, "__repr__", None)
265 if issubclass(typ, dict) and r is dict.__repr__:
266 if not object:
267 return "{}", True, False
268 objid = _id(object)
269 if maxlevels and level >= maxlevels:
270 return "{...}", False, objid in context
271 if objid in context:
272 return _recursion(object), False, True
273 context[objid] = 1
274 readable = True
275 recursive = False
276 components = []
277 append = components.append
278 level += 1
279 saferepr = _safe_repr
280 for k, v in _sorted(object.items()):
281 krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
282 vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
283 append("%s: %s" % (krepr, vrepr))
284 readable = readable and kreadable and vreadable
285 if krecur or vrecur:
286 recursive = True
287 del context[objid]
288 return "{%s}" % _commajoin(components), readable, recursive
289
290 if (issubclass(typ, list) and r is list.__repr__) or \
291 (issubclass(typ, tuple) and r is tuple.__repr__):
292 if issubclass(typ, list):
293 if not object:
294 return "[]", True, False
295 format = "[%s]"
296 elif _len(object) == 1:
297 format = "(%s,)"
298 else:
299 if not object:
300 return "()", True, False
301 format = "(%s)"
302 objid = _id(object)
303 if maxlevels and level >= maxlevels:
304 return format % "...", False, objid in context
305 if objid in context:
306 return _recursion(object), False, True
307 context[objid] = 1
308 readable = True
309 recursive = False
310 components = []
311 append = components.append
312 level += 1
313 for o in object:
314 orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)
315 append(orepr)
316 if not oreadable:
317 readable = False
318 if orecur:
319 recursive = True
320 del context[objid]
321 return format % _commajoin(components), readable, recursive
322
323 rep = repr(object)
324 return rep, (rep and not rep.startswith('<')), False
325
326
327def _recursion(object):
328 return ("<Recursion on %s with id=%s>"
329 % (_type(object).__name__, _id(object)))
330
331
332def _perfcheck(object=None):
333 import time
334 if object is None:
335 object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
336 p = PrettyPrinter()
337 t1 = time.time()
338 _safe_repr(object, {}, None, 0)
339 t2 = time.time()
340 p.pformat(object)
341 t3 = time.time()
342 print "_safe_repr:", t2 - t1
343 print "pformat:", t3 - t2
344
345if __name__ == "__main__":
346 _perfcheck()
Note: See TracBrowser for help on using the repository browser.