Merged release21-maint changes.
[python/dscho.git] / Lib / pprint.py
blob351323be6b5688f73522558ce130d1485ae8ef32
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)
52 def pformat(object):
53 """Format a Python object into a pretty-printed representation."""
54 return PrettyPrinter().pformat(object)
56 def saferepr(object):
57 """Version of repr() which can handle recursive data structures."""
58 return _safe_repr(object, {})[0]
60 def isreadable(object):
61 """Determine if saferepr(object) is readable by eval()."""
62 return _safe_repr(object, {})[1]
64 def isrecursive(object):
65 """Determine if object requires a recursive representation."""
66 return _safe_repr(object, {})[2]
68 class PrettyPrinter:
69 def __init__(self, indent=1, width=80, depth=None, stream=None):
70 """Handle pretty printing operations onto a stream using a set of
71 configured parameters.
73 indent
74 Number of spaces to indent for each level of nesting.
76 width
77 Attempted maximum number of columns in the output.
79 depth
80 The maximum depth to print out nested structures.
82 stream
83 The desired output stream. If omitted (or false), the standard
84 output stream available at construction will be used.
86 """
87 indent = int(indent)
88 width = int(width)
89 assert indent >= 0
90 assert depth is None or depth > 0, "depth must be > 0"
91 assert width
92 self.__depth = depth
93 self.__indent_per_level = indent
94 self.__width = width
95 if stream:
96 self.__stream = stream
97 else:
98 import sys
99 self.__stream = sys.stdout
101 def pprint(self, object):
102 self.__stream.write(self.pformat(object) + "\n")
104 def pformat(self, object):
105 sio = StringIO()
106 self.__format(object, sio, 0, 0, {}, 0)
107 return sio.getvalue()
109 def isrecursive(self, object):
110 self.__recursive = 0
111 self.pformat(object)
112 return self.__recursive
114 def isreadable(self, object):
115 self.__recursive = 0
116 self.__readable = 1
117 self.pformat(object)
118 return self.__readable and not self.__recursive
120 def __format(self, object, stream, indent, allowance, context, level):
121 level = level + 1
122 if context.has_key(id(object)):
123 object = _Recursion(object)
124 self.__recursive = 1
125 rep = self.__repr(object, context, level - 1)
126 objid = id(object)
127 context[objid] = 1
128 typ = type(object)
129 sepLines = len(rep) > (self.__width - 1 - indent - allowance)
131 if sepLines and typ in (ListType, TupleType):
132 # Pretty-print the sequence.
133 stream.write((typ is ListType) and '[' or '(')
134 if self.__indent_per_level > 1:
135 stream.write((self.__indent_per_level - 1) * ' ')
136 length = len(object)
137 if length:
138 indent = indent + self.__indent_per_level
139 self.__format(object[0], stream, indent, allowance + 1,
140 context, level)
141 if length > 1:
142 for ent in object[1:]:
143 stream.write(',\n' + ' '*indent)
144 self.__format(ent, stream, indent,
145 allowance + 1, context, level)
146 indent = indent - self.__indent_per_level
147 if typ is TupleType and length == 1:
148 stream.write(',')
149 stream.write(((typ is ListType) and ']') or ')')
151 elif sepLines and typ is DictType:
152 stream.write('{')
153 if self.__indent_per_level > 1:
154 stream.write((self.__indent_per_level - 1) * ' ')
155 length = len(object)
156 if length:
157 indent = indent + self.__indent_per_level
158 items = object.items()
159 items.sort()
160 key, ent = items[0]
161 rep = self.__repr(key, context, level) + ': '
162 stream.write(rep)
163 self.__format(ent, stream, indent + len(rep),
164 allowance + 1, context, level)
165 if len(items) > 1:
166 for key, ent in items[1:]:
167 rep = self.__repr(key, context, level) + ': '
168 stream.write(',\n' + ' '*indent + rep)
169 self.__format(ent, stream, indent + len(rep),
170 allowance + 1, context, level)
171 indent = indent - self.__indent_per_level
172 stream.write('}')
174 else:
175 stream.write(rep)
177 del context[objid]
179 def __repr(self, object, context, level):
180 repr, readable, recursive = _safe_repr(object, context,
181 self.__depth, level)
182 if not readable:
183 self.__readable = 0
184 if recursive:
185 self.__recursive = 1
186 return repr
188 # Return triple (repr_string, isreadable, isrecursive).
190 def _safe_repr(object, context, maxlevels=None, level=0):
191 level += 1
192 typ = type(object)
193 if not (typ in (DictType, ListType, TupleType) and object):
194 rep = `object`
195 return rep, (rep and (rep[0] != '<')), 0
197 if context.has_key(id(object)):
198 return `_Recursion(object)`, 0, 1
199 objid = id(object)
200 context[objid] = 1
202 readable = 1
203 recursive = 0
204 startchar, endchar = {ListType: "[]",
205 TupleType: "()",
206 DictType: "{}"}[typ]
207 if maxlevels and level > maxlevels:
208 with_commas = "..."
209 readable = 0
211 elif typ is DictType:
212 components = []
213 for k, v in object.iteritems():
214 krepr, kreadable, krecur = _safe_repr(k, context, maxlevels,
215 level)
216 vrepr, vreadable, vrecur = _safe_repr(v, context, maxlevels,
217 level)
218 components.append("%s: %s" % (krepr, vrepr))
219 readable = readable and kreadable and vreadable
220 recursive = recursive or krecur or vrecur
221 with_commas = ", ".join(components)
223 else: # list or tuple
224 assert typ in (ListType, TupleType)
225 components = []
226 for element in object:
227 subrepr, subreadable, subrecur = _safe_repr(
228 element, context, maxlevels, level)
229 components.append(subrepr)
230 readable = readable and subreadable
231 recursive = recursive or subrecur
232 if len(components) == 1 and typ is TupleType:
233 components[0] += ","
234 with_commas = ", ".join(components)
236 s = "%s%s%s" % (startchar, with_commas, endchar)
237 del context[objid]
238 return s, readable and not recursive, recursive
240 class _Recursion:
241 # represent a recursive relationship; really only used for the __repr__()
242 # method...
243 def __init__(self, object):
244 self.__repr = "<Recursion on %s with id=%s>" \
245 % (type(object).__name__, id(object))
247 def __repr__(self):
248 return self.__repr