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.
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.sydout].
32 Generate a 'standard' repr()-like value, but protect against recursive
37 from types
import DictType
, ListType
, TupleType
40 from cStringIO
import StringIO
42 from StringIO
import StringIO
44 __all__
= ["pprint","pformat","isreadable","isrecursive","saferepr",
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 """Format a Python object into a pretty-printed representation."""
54 return PrettyPrinter().pformat(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]
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.
74 Number of spaces to indent for each level of nesting.
77 Attempted maximum number of columns in the output.
80 The maximum depth to print out nested structures.
83 The desired output stream. If omitted (or false), the standard
84 output stream available at construction will be used.
90 assert depth
is None or depth
> 0, "depth must be > 0"
93 self
.__indent
_per
_level
= indent
96 self
.__stream
= stream
99 self
.__stream
= sys
.stdout
101 def pprint(self
, object):
102 self
.__stream
.write(self
.pformat(object) + "\n")
104 def pformat(self
, object):
106 self
.__format
(object, sio
, 0, 0, {}, 0)
107 return sio
.getvalue()
109 def isrecursive(self
, object):
112 return self
.__recursive
114 def isreadable(self
, object):
118 return self
.__readable
and not self
.__recursive
120 def __format(self
, object, stream
, indent
, allowance
, context
, level
):
122 if context
.has_key(id(object)):
123 object = _Recursion(object)
125 rep
= self
.__repr
(object, context
, level
- 1)
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) * ' ')
138 indent
= indent
+ self
.__indent
_per
_level
139 self
.__format
(object[0], stream
, indent
, allowance
+ 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:
149 stream
.write(((typ
is ListType
) and ']') or ')')
151 elif sepLines
and typ
is DictType
:
153 if self
.__indent
_per
_level
> 1:
154 stream
.write((self
.__indent
_per
_level
- 1) * ' ')
157 indent
= indent
+ self
.__indent
_per
_level
158 items
= object.items()
161 rep
= self
.__repr
(key
, context
, level
) + ': '
163 self
.__format
(ent
, stream
, indent
+ len(rep
),
164 allowance
+ 1, context
, level
)
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
179 def __repr(self
, object, context
, level
):
180 repr, readable
, recursive
= _safe_repr(object, context
,
188 # Return triple (repr_string, isreadable, isrecursive).
190 def _safe_repr(object, context
, maxlevels
=None, level
=0):
193 if not (typ
in (DictType
, ListType
, TupleType
) and object):
195 return rep
, (rep
and (rep
[0] != '<')), 0
197 if context
.has_key(id(object)):
198 return `
_Recursion(object)`
, 0, 1
204 startchar
, endchar
= {ListType
: "[]",
207 if maxlevels
and level
> maxlevels
:
211 elif typ
is DictType
:
213 for k
, v
in object.iteritems():
214 krepr
, kreadable
, krecur
= _safe_repr(k
, context
, maxlevels
,
216 vrepr
, vreadable
, vrecur
= _safe_repr(v
, context
, maxlevels
,
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
)
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
:
234 with_commas
= ", ".join(components
)
236 s
= "%s%s%s" % (startchar
, with_commas
, endchar
)
238 return s
, readable
and not recursive
, recursive
241 # represent a recursive relationship; really only used for the __repr__()
243 def __init__(self
, object):
244 self
.__repr
= "<Recursion on %s with id=%s>" \
245 % (type(object).__name
__, id(object))