Bump version to 0.9.1.
[python/dscho.git] / Lib / pprint.py
blob8e10e9d9dc84d579385ad8aaac1d8eda9c6450d7
1 # Author: Fred L. Drake, Jr.
2 # fdrake@cnri.reston.va.us, 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.sydout].
31 saferepr()
32 Generate a 'standard' repr()-like value, but protect against recursive
33 data structures.
35 """
37 from types import DictType, ListType, TupleType
39 try:
40 from cStringIO import StringIO
41 except ImportError:
42 from StringIO import StringIO
45 def pprint(object, stream=None):
46 """Pretty-print a Python object to a stream [default is sys.sydout]."""
47 printer = PrettyPrinter(stream=stream)
48 printer.pprint(object)
51 def pformat(object):
52 """Format a Python object into a pretty-printed representation."""
53 return PrettyPrinter().pformat(object)
56 def isreadable(object):
57 """Determine if saferepr(object) is readable by eval()."""
58 return PrettyPrinter().isreadable(object)
61 def isrecursive(object):
62 """Determine if object requires a recursive representation."""
63 return PrettyPrinter().isrecursive(object)
66 def saferepr(object):
67 """Version of repr() which can handle recursive data structures."""
68 return _safe_repr(object, {})[0]
71 class PrettyPrinter:
72 def __init__(self, indent=1, width=80, depth=None, stream=None):
73 """Handle pretty printing operations onto a stream using a set of
74 configured parameters.
76 indent
77 Number of spaces to indent for each level of nesting.
79 width
80 Attempted maximum number of columns in the output.
82 depth
83 The maximum depth to print out nested structures.
85 stream
86 The desired output stream. If omitted (or false), the standard
87 output stream available at construction will be used.
89 """
90 indent = int(indent)
91 width = int(width)
92 assert indent >= 0
93 assert (not depth) or depth > 0, "depth may not be negative"
94 assert width
95 self.__depth = depth
96 self.__indent_per_level = indent
97 self.__width = width
98 if stream:
99 self.__stream = stream
100 else:
101 import sys
102 self.__stream = sys.stdout
104 def pprint(self, object):
105 self.__stream.write(self.pformat(object) + "\n")
107 def pformat(self, object):
108 sio = StringIO()
109 self.__format(object, sio, 0, 0, {}, 0)
110 return sio.getvalue()
112 def isrecursive(self, object):
113 self.__recursive = 0
114 self.pformat(object)
115 return self.__recursive
117 def isreadable(self, object):
118 self.__recursive = 0
119 self.__readable = 1
120 self.pformat(object)
121 return self.__readable and not self.__recursive
123 def __format(self, object, stream, indent, allowance, context, level):
124 level = level + 1
125 if context.has_key(id(object)):
126 object = _Recursion(object)
127 self.__recursive = 1
128 rep = self.__repr(object, context, level - 1)
129 objid = id(object)
130 context[objid] = 1
131 typ = type(object)
132 sepLines = len(rep) > (self.__width - 1 - indent - allowance)
134 if sepLines and typ in (ListType, TupleType):
135 # Pretty-print the sequence.
136 stream.write((typ is ListType) and '[' or '(')
137 if self.__indent_per_level > 1:
138 stream.write((self.__indent_per_level - 1) * ' ')
139 length = len(object)
140 if length:
141 indent = indent + self.__indent_per_level
142 self.__format(object[0], stream, indent, allowance + 1,
143 context, level)
144 if length > 1:
145 for ent in object[1:]:
146 stream.write(',\n' + ' '*indent)
147 self.__format(ent, stream, indent,
148 allowance + 1, context, level)
149 indent = indent - self.__indent_per_level
150 if typ is TupleType and length == 1:
151 stream.write(',')
152 stream.write(((typ is ListType) and ']') or ')')
154 elif sepLines and typ is DictType:
155 stream.write('{')
156 if self.__indent_per_level > 1:
157 stream.write((self.__indent_per_level - 1) * ' ')
158 length = len(object)
159 if length:
160 indent = indent + self.__indent_per_level
161 items = object.items()
162 items.sort()
163 key, ent = items[0]
164 rep = self.__repr(key, context, level) + ': '
165 stream.write(rep)
166 self.__format(ent, stream, indent + len(rep),
167 allowance + 1, context, level)
168 if len(items) > 1:
169 for key, ent in items[1:]:
170 rep = self.__repr(key, context, level) + ': '
171 stream.write(',\n' + ' '*indent + rep)
172 self.__format(ent, stream, indent + len(rep),
173 allowance + 1, context, level)
174 indent = indent - self.__indent_per_level
175 stream.write('}')
177 else:
178 stream.write(rep)
180 del context[objid]
182 def __repr(self, object, context, level):
183 repr, readable = _safe_repr(object, context, self.__depth, level)
184 if not readable:
185 self.__readable = 0
186 return repr
189 def _safe_repr(object, context, maxlevels=None, level=0):
190 level = level + 1
191 typ = type(object)
192 if not (typ in (DictType, ListType, TupleType) and object):
193 rep = `object`
194 return rep, (rep and (rep[0] != '<'))
195 if context.has_key(id(object)):
196 return `_Recursion(object)`, 0
197 objid = id(object)
198 context[objid] = 1
199 readable = 1
200 if typ is DictType:
201 if maxlevels and level >= maxlevels:
202 s = "{...}"
203 readable = 0
204 else:
205 items = object.items()
206 k, v = items[0]
207 krepr, kreadable = _safe_repr(k, context, maxlevels, level)
208 vrepr, vreadable = _safe_repr(v, context, maxlevels, level)
209 readable = readable and kreadable and vreadable
210 s = "{%s: %s" % (krepr, vrepr)
211 for k, v in items[1:]:
212 krepr, kreadable = _safe_repr(k, context, maxlevels, level)
213 vrepr, vreadable = _safe_repr(v, context, maxlevels, level)
214 readable = readable and kreadable and vreadable
215 s = "%s, %s: %s" % (s, krepr, vrepr)
216 s = s + "}"
217 else:
218 s, term = (typ is ListType) and ('[', ']') or ('(', ')')
219 if maxlevels and level >= maxlevels:
220 s = s + "..."
221 readable = 0
222 else:
223 subrepr, subreadable = _safe_repr(
224 object[0], context, maxlevels, level)
225 readable = readable and subreadable
226 s = s + subrepr
227 tail = object[1:]
228 if not tail:
229 if typ is TupleType:
230 s = s + ','
231 for ent in tail:
232 subrepr, subreadable = _safe_repr(
233 ent, context, maxlevels, level)
234 readable = readable and subreadable
235 s = "%s, %s" % (s, subrepr)
236 s = s + term
237 del context[objid]
238 return s, readable
241 class _Recursion:
242 # represent a recursive relationship; really only used for the __repr__()
243 # method...
244 def __init__(self, object):
245 self.__repr = "<Recursion on %s with id=%s>" \
246 % (type(object).__name__, id(object))
248 def __repr__(self):
249 return self.__repr