Updated for 2.1a3
[python/dscho.git] / Lib / pprint.py
blob814ca48af0708e5b3b0659e0eb938020dbbc2525
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
44 __all__ = ["pprint","pformat","isreadable","isrecursive","saferepr",
45 "PrettyPrinter"]
47 def pprint(object, stream=None):
48 """Pretty-print a Python object to a stream [default is sys.sydout]."""
49 printer = PrettyPrinter(stream=stream)
50 printer.pprint(object)
53 def pformat(object):
54 """Format a Python object into a pretty-printed representation."""
55 return PrettyPrinter().pformat(object)
58 def isreadable(object):
59 """Determine if saferepr(object) is readable by eval()."""
60 return PrettyPrinter().isreadable(object)
63 def isrecursive(object):
64 """Determine if object requires a recursive representation."""
65 return PrettyPrinter().isrecursive(object)
68 def saferepr(object):
69 """Version of repr() which can handle recursive data structures."""
70 return _safe_repr(object, {})[0]
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
95 assert (not depth) or depth > 0, "depth may not be negative"
96 assert width
97 self.__depth = depth
98 self.__indent_per_level = indent
99 self.__width = width
100 if stream:
101 self.__stream = stream
102 else:
103 import sys
104 self.__stream = sys.stdout
106 def pprint(self, object):
107 self.__stream.write(self.pformat(object) + "\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 self.__recursive = 0
116 self.pformat(object)
117 return self.__recursive
119 def isreadable(self, object):
120 self.__recursive = 0
121 self.__readable = 1
122 self.pformat(object)
123 return self.__readable and not self.__recursive
125 def __format(self, object, stream, indent, allowance, context, level):
126 level = level + 1
127 if context.has_key(id(object)):
128 object = _Recursion(object)
129 self.__recursive = 1
130 rep = self.__repr(object, context, level - 1)
131 objid = id(object)
132 context[objid] = 1
133 typ = type(object)
134 sepLines = len(rep) > (self.__width - 1 - indent - allowance)
136 if sepLines and typ in (ListType, TupleType):
137 # Pretty-print the sequence.
138 stream.write((typ is ListType) and '[' or '(')
139 if self.__indent_per_level > 1:
140 stream.write((self.__indent_per_level - 1) * ' ')
141 length = len(object)
142 if length:
143 indent = indent + self.__indent_per_level
144 self.__format(object[0], stream, indent, allowance + 1,
145 context, level)
146 if length > 1:
147 for ent in object[1:]:
148 stream.write(',\n' + ' '*indent)
149 self.__format(ent, stream, indent,
150 allowance + 1, context, level)
151 indent = indent - self.__indent_per_level
152 if typ is TupleType and length == 1:
153 stream.write(',')
154 stream.write(((typ is ListType) and ']') or ')')
156 elif sepLines and typ is DictType:
157 stream.write('{')
158 if self.__indent_per_level > 1:
159 stream.write((self.__indent_per_level - 1) * ' ')
160 length = len(object)
161 if length:
162 indent = indent + self.__indent_per_level
163 items = object.items()
164 items.sort()
165 key, ent = items[0]
166 rep = self.__repr(key, context, level) + ': '
167 stream.write(rep)
168 self.__format(ent, stream, indent + len(rep),
169 allowance + 1, context, level)
170 if len(items) > 1:
171 for key, ent in items[1:]:
172 rep = self.__repr(key, context, level) + ': '
173 stream.write(',\n' + ' '*indent + rep)
174 self.__format(ent, stream, indent + len(rep),
175 allowance + 1, context, level)
176 indent = indent - self.__indent_per_level
177 stream.write('}')
179 else:
180 stream.write(rep)
182 del context[objid]
184 def __repr(self, object, context, level):
185 repr, readable = _safe_repr(object, context, self.__depth, level)
186 if not readable:
187 self.__readable = 0
188 return repr
191 def _safe_repr(object, context, maxlevels=None, level=0):
192 level = level + 1
193 typ = type(object)
194 if not (typ in (DictType, ListType, TupleType) and object):
195 rep = `object`
196 return rep, (rep and (rep[0] != '<'))
197 if context.has_key(id(object)):
198 return `_Recursion(object)`, 0
199 objid = id(object)
200 context[objid] = 1
201 readable = 1
202 if typ is DictType:
203 if maxlevels and level >= maxlevels:
204 s = "{...}"
205 readable = 0
206 else:
207 items = object.items()
208 k, v = items[0]
209 krepr, kreadable = _safe_repr(k, context, maxlevels, level)
210 vrepr, vreadable = _safe_repr(v, context, maxlevels, level)
211 readable = readable and kreadable and vreadable
212 s = "{%s: %s" % (krepr, vrepr)
213 for k, v in items[1:]:
214 krepr, kreadable = _safe_repr(k, context, maxlevels, level)
215 vrepr, vreadable = _safe_repr(v, context, maxlevels, level)
216 readable = readable and kreadable and vreadable
217 s = "%s, %s: %s" % (s, krepr, vrepr)
218 s = s + "}"
219 else:
220 s, term = (typ is ListType) and ('[', ']') or ('(', ')')
221 if maxlevels and level >= maxlevels:
222 s = s + "..."
223 readable = 0
224 else:
225 subrepr, subreadable = _safe_repr(
226 object[0], context, maxlevels, level)
227 readable = readable and subreadable
228 s = s + subrepr
229 tail = object[1:]
230 if not tail:
231 if typ is TupleType:
232 s = s + ','
233 for ent in tail:
234 subrepr, subreadable = _safe_repr(
235 ent, context, maxlevels, level)
236 readable = readable and subreadable
237 s = "%s, %s" % (s, subrepr)
238 s = s + term
239 del context[objid]
240 return s, readable
243 class _Recursion:
244 # represent a recursive relationship; really only used for the __repr__()
245 # method...
246 def __init__(self, object):
247 self.__repr = "<Recursion on %s with id=%s>" \
248 % (type(object).__name__, id(object))
250 def __repr__(self):
251 return self.__repr