1
# Author: Fred L. Drake, Jr.
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.
19
Handle pretty-printing operations onto a stream using a configured
20
set of formatting parameters.
26
Format a Python object into a pretty-printed representation.
29
Pretty-print a Python object to a stream [default is sys.stdout].
32
Generate a 'standard' repr()-like value, but protect against recursive
39
from cStringIO import StringIO as _StringIO
41
__all__ = ["pprint","pformat","isreadable","isrecursive","saferepr",
44
# cache these for faster access:
45
_commajoin = ", ".join
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)
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]
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.
79
Number of spaces to indent for each level of nesting.
82
Attempted maximum number of columns in the output.
85
The maximum depth to print out nested structures.
88
The desired output stream. If omitted (or false), the standard
89
output stream available at construction will be used.
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"
98
self._indent_per_level = indent
100
if stream is not None:
101
self._stream = stream
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):
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):
125
stream.write(_recursion(object))
126
self._recursive = True
127
self._readable = False
129
rep = self._repr(object, context, level - 1)
131
sepLines = _len(rep) > (self._width - 1 - indent - allowance)
134
if self._depth and level > self._depth:
138
r = getattr(typ, "__repr__", None)
139
if issubclass(typ, dict) and r is dict.__repr__:
141
if self._indent_per_level > 1:
142
write((self._indent_per_level - 1) * ' ')
143
length = _len(object)
146
indent = indent + self._indent_per_level
147
items = object.items()
150
rep = self._repr(key, context, level)
153
self._format(ent, stream, indent + _len(rep) + 2,
154
allowance + 1, context, level)
156
for key, ent in items[1:]:
157
rep = self._repr(key, context, level)
159
write(',\n%s%s: ' % (' '*indent, rep))
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
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):
178
elif issubclass(typ, set):
184
object = sorted(object)
186
elif issubclass(typ, frozenset):
192
object = sorted(object)
197
if self._indent_per_level > 1 and sepLines:
198
write((self._indent_per_level - 1) * ' ')
201
indent = indent + self._indent_per_level
202
self._format(object[0], stream, indent, allowance + 1,
205
for ent in object[1:]:
207
write(',\n' + ' '*indent)
210
self._format(ent, stream, indent,
211
allowance + 1, context, level)
212
indent = indent - self._indent_per_level
214
if issubclass(typ, tuple) and length == 1:
221
def _repr(self, object, context, level):
222
repr, readable, recursive = self.format(object, context.copy(),
225
self._readable = False
227
self._recursive = True
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):
243
if 'locale' not in _sys.modules:
244
return repr(object), True, False
245
if "'" in object and '"' not in object:
247
quotes = {'"': '\\"'}
250
quotes = {"'": "\\'"}
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__:
264
return "{}", True, False
266
if maxlevels and level >= maxlevels:
267
return "{...}", False, objid in context
269
return _recursion(object), False, True
274
append = components.append
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
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):
291
return "[]", True, False
293
elif _len(object) == 1:
297
return "()", True, False
300
if maxlevels and level >= maxlevels:
301
return format % "...", False, objid in context
303
return _recursion(object), False, True
308
append = components.append
311
orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)
318
return format % _commajoin(components), readable, recursive
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):
332
object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
335
_safe_repr(object, {}, None, 0)
339
print "_safe_repr:", t2 - t1
340
print "pformat:", t3 - t2
342
if __name__ == "__main__":