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 modelled 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
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)
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)
67 """Version of repr() which can handle recursive data structures."""
68 return _safe_repr(object, {})[0]
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.
77 Number of spaces to indent for each level of nesting.
80 Attempted maximum number of columns in the output.
83 The maximum depth to print out nested structures.
86 The desired output stream. If omitted (or false), the standard
87 output stream available at construction will be used.
93 assert (not depth
) or depth
> 0, "depth may not be negative"
96 self
.__indent
_per
_level
= indent
99 self
.__stream
= stream
102 self
.__stream
= sys
.stdout
104 def pprint(self
, object):
105 self
.__stream
.write(self
.pformat(object) + "\n")
107 def pformat(self
, object):
109 self
.__format
(object, sio
, 0, 0, {}, 0)
110 return sio
.getvalue()
112 def isrecursive(self
, object):
115 return self
.__recursive
117 def isreadable(self
, object):
121 return self
.__readable
and not self
.__recursive
123 def __format(self
, object, stream
, indent
, allowance
, context
, level
):
125 if context
.has_key(id(object)):
126 object = _Recursion(object)
128 rep
= self
.__repr
(object, context
, level
- 1)
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) * ' ')
141 indent
= indent
+ self
.__indent
_per
_level
142 self
.__format
(object[0], stream
, indent
, allowance
+ 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:
152 stream
.write(((typ
is ListType
) and ']') or ')')
154 elif sepLines
and typ
is DictType
:
156 if self
.__indent
_per
_level
> 1:
157 stream
.write((self
.__indent
_per
_level
- 1) * ' ')
160 indent
= indent
+ self
.__indent
_per
_level
161 items
= object.items()
164 rep
= self
.__repr
(key
, context
, level
) + ': '
166 self
.__format
(ent
, stream
, indent
+ len(rep
),
167 allowance
+ 1, context
, level
)
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
182 def __repr(self
, object, context
, level
):
183 repr, readable
= _safe_repr(object, context
, self
.__depth
, level
)
189 def _safe_repr(object, context
, maxlevels
=None, level
=0):
192 if not (typ
in (DictType
, ListType
, TupleType
) and object):
194 return rep
, (rep
and (rep
[0] != '<'))
195 if context
.has_key(id(object)):
196 return `
_Recursion(object)`
, 0
201 if maxlevels
and level
>= maxlevels
:
205 items
= object.items()
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
)
218 s
, term
= (typ
is ListType
) and ('[', ']') or ('(', ')')
219 if maxlevels
and level
>= maxlevels
:
223 subrepr
, subreadable
= _safe_repr(
224 object[0], context
, maxlevels
, level
)
225 readable
= readable
and subreadable
232 subrepr
, subreadable
= _safe_repr(
233 ent
, context
, maxlevels
, level
)
234 readable
= readable
and subreadable
235 s
= "%s, %s" % (s
, subrepr
)
242 # represent a recursive relationship; really only used for the __repr__()
244 def __init__(self
, object):
245 self
.__repr
= "<Recursion on %s with id=%s>" \
246 % (type(object).__name
__, id(object))