blob: 814ca48af0708e5b3b0659e0eb938020dbbc2525 [file] [log] [blame]
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001# Author: Fred L. Drake, Jr.
2# fdrake@cnri.reston.va.us, fdrake@acm.org
Guido van Rossum5e92aff1997-04-16 00:49:59 +00003#
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
Thomas Wouters7e474022000-07-16 12:04:32 +00007# tuples with fairly non-descriptive content. This is modeled very much
Guido van Rossum5e92aff1997-04-16 00:49:59 +00008# 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
Fred Drakea89fda01997-04-16 16:59:30 +000015Classes
16-------
17
18PrettyPrinter()
19 Handle pretty-printing operations onto a stream using a configured
20 set of formatting parameters.
21
Guido van Rossum5e92aff1997-04-16 00:49:59 +000022Functions
23---------
24
25pformat()
26 Format a Python object into a pretty-printed representation.
27
28pprint()
Fred Drakea89fda01997-04-16 16:59:30 +000029 Pretty-print a Python object to a stream [default is sys.sydout].
Guido van Rossum5e92aff1997-04-16 00:49:59 +000030
Fred Drakea89fda01997-04-16 16:59:30 +000031saferepr()
32 Generate a 'standard' repr()-like value, but protect against recursive
33 data structures.
Guido van Rossum5e92aff1997-04-16 00:49:59 +000034
35"""
36
Guido van Rossum5e92aff1997-04-16 00:49:59 +000037from types import DictType, ListType, TupleType
38
Fred Drakea89fda01997-04-16 16:59:30 +000039try:
40 from cStringIO import StringIO
41except ImportError:
42 from StringIO import StringIO
Guido van Rossum5e92aff1997-04-16 00:49:59 +000043
Skip Montanaroc62c81e2001-02-12 02:00:42 +000044__all__ = ["pprint","pformat","isreadable","isrecursive","saferepr",
45 "PrettyPrinter"]
Guido van Rossum5e92aff1997-04-16 00:49:59 +000046
Fred Drakea89fda01997-04-16 16:59:30 +000047def 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)
Guido van Rossum5e92aff1997-04-16 00:49:59 +000051
Guido van Rossum5e92aff1997-04-16 00:49:59 +000052
Fred Drakea89fda01997-04-16 16:59:30 +000053def pformat(object):
54 """Format a Python object into a pretty-printed representation."""
55 return PrettyPrinter().pformat(object)
Guido van Rossum5e92aff1997-04-16 00:49:59 +000056
Guido van Rossum5e92aff1997-04-16 00:49:59 +000057
Fred Drakee0ffabe1997-07-18 20:42:39 +000058def isreadable(object):
59 """Determine if saferepr(object) is readable by eval()."""
60 return PrettyPrinter().isreadable(object)
61
62
63def isrecursive(object):
64 """Determine if object requires a recursive representation."""
65 return PrettyPrinter().isrecursive(object)
66
67
Fred Drakea89fda01997-04-16 16:59:30 +000068def saferepr(object):
69 """Version of repr() which can handle recursive data structures."""
Fred Drakee0ffabe1997-07-18 20:42:39 +000070 return _safe_repr(object, {})[0]
Guido van Rossum5e92aff1997-04-16 00:49:59 +000071
Guido van Rossum5e92aff1997-04-16 00:49:59 +000072
Fred Drakea89fda01997-04-16 16:59:30 +000073class PrettyPrinter:
74 def __init__(self, indent=1, width=80, depth=None, stream=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000075 """Handle pretty printing operations onto a stream using a set of
76 configured parameters.
Guido van Rossum5e92aff1997-04-16 00:49:59 +000077
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000078 indent
79 Number of spaces to indent for each level of nesting.
Guido van Rossum5e92aff1997-04-16 00:49:59 +000080
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000081 width
82 Attempted maximum number of columns in the output.
Guido van Rossum5e92aff1997-04-16 00:49:59 +000083
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000084 depth
85 The maximum depth to print out nested structures.
Guido van Rossum5e92aff1997-04-16 00:49:59 +000086
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000087 stream
88 The desired output stream. If omitted (or false), the standard
89 output stream available at construction will be used.
Guido van Rossum5e92aff1997-04-16 00:49:59 +000090
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000091 """
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
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000105
Fred Drakea89fda01997-04-16 16:59:30 +0000106 def pprint(self, object):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000107 self.__stream.write(self.pformat(object) + "\n")
Fred Drakea89fda01997-04-16 16:59:30 +0000108
109 def pformat(self, object):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000110 sio = StringIO()
111 self.__format(object, sio, 0, 0, {}, 0)
112 return sio.getvalue()
Fred Drakea89fda01997-04-16 16:59:30 +0000113
Fred Drakee0ffabe1997-07-18 20:42:39 +0000114 def isrecursive(self, object):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000115 self.__recursive = 0
116 self.pformat(object)
117 return self.__recursive
Fred Drakee0ffabe1997-07-18 20:42:39 +0000118
119 def isreadable(self, object):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000120 self.__recursive = 0
121 self.__readable = 1
122 self.pformat(object)
123 return self.__readable and not self.__recursive
Fred Drakee0ffabe1997-07-18 20:42:39 +0000124
Fred Drakea89fda01997-04-16 16:59:30 +0000125 def __format(self, object, stream, indent, allowance, context, level):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000126 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)
Fred Drakea89fda01997-04-16 16:59:30 +0000135
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000136 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)
Fred Drakefbff97a1999-12-22 21:52:32 +0000146 if length > 1:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000147 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 ')')
Fred Drakea89fda01997-04-16 16:59:30 +0000155
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000156 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('}')
Fred Drakea89fda01997-04-16 16:59:30 +0000178
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000179 else:
180 stream.write(rep)
Guido van Rossum183fd401999-09-02 15:09:44 +0000181
182 del context[objid]
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000183
Fred Drakea89fda01997-04-16 16:59:30 +0000184 def __repr(self, object, context, level):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000185 repr, readable = _safe_repr(object, context, self.__depth, level)
186 if not readable:
187 self.__readable = 0
188 return repr
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000189
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000190
Fred Drakef39d0511997-04-16 18:55:58 +0000191def _safe_repr(object, context, maxlevels=None, level=0):
Fred Drakea89fda01997-04-16 16:59:30 +0000192 level = level + 1
193 typ = type(object)
194 if not (typ in (DictType, ListType, TupleType) and object):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000195 rep = `object`
Fred Draked804f4e1999-02-17 17:30:52 +0000196 return rep, (rep and (rep[0] != '<'))
Fred Drakef39d0511997-04-16 18:55:58 +0000197 if context.has_key(id(object)):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000198 return `_Recursion(object)`, 0
Fred Drakea89fda01997-04-16 16:59:30 +0000199 objid = id(object)
200 context[objid] = 1
Fred Draked804f4e1999-02-17 17:30:52 +0000201 readable = 1
Fred Drakea89fda01997-04-16 16:59:30 +0000202 if typ is DictType:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000203 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 + "}"
Fred Drakea89fda01997-04-16 16:59:30 +0000219 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000220 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
Fred Drakea89fda01997-04-16 16:59:30 +0000239 del context[objid]
Fred Drakee0ffabe1997-07-18 20:42:39 +0000240 return s, readable
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000241
Fred Drakea89fda01997-04-16 16:59:30 +0000242
243class _Recursion:
244 # represent a recursive relationship; really only used for the __repr__()
245 # method...
246 def __init__(self, object):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000247 self.__repr = "<Recursion on %s with id=%s>" \
248 % (type(object).__name__, id(object))
Fred Drakea89fda01997-04-16 16:59:30 +0000249
250 def __repr__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000251 return self.__repr