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)
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)
69 """Version of repr() which can handle recursive data structures."""
70 return _safe_repr(object, {})[0]
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.
79 Number of spaces to indent for each level of nesting.
82 Attempted maximum number of columns in the output.
85 The maximum depth to print out nested structures.
88 The desired output stream. If omitted (or false), the standard
89 output stream available at construction will be used.
95 assert (not depth
) or depth
> 0, "depth may not be negative"
98 self
.__indent
_per
_level
= indent
101 self
.__stream
= stream
104 self
.__stream
= sys
.stdout
106 def pprint(self
, object):
107 self
.__stream
.write(self
.pformat(object) + "\n")
109 def pformat(self
, object):
111 self
.__format
(object, sio
, 0, 0, {}, 0)
112 return sio
.getvalue()
114 def isrecursive(self
, object):
117 return self
.__recursive
119 def isreadable(self
, object):
123 return self
.__readable
and not self
.__recursive
125 def __format(self
, object, stream
, indent
, allowance
, context
, level
):
127 if context
.has_key(id(object)):
128 object = _Recursion(object)
130 rep
= self
.__repr
(object, context
, level
- 1)
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) * ' ')
143 indent
= indent
+ self
.__indent
_per
_level
144 self
.__format
(object[0], stream
, indent
, allowance
+ 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:
154 stream
.write(((typ
is ListType
) and ']') or ')')
156 elif sepLines
and typ
is DictType
:
158 if self
.__indent
_per
_level
> 1:
159 stream
.write((self
.__indent
_per
_level
- 1) * ' ')
162 indent
= indent
+ self
.__indent
_per
_level
163 items
= object.items()
166 rep
= self
.__repr
(key
, context
, level
) + ': '
168 self
.__format
(ent
, stream
, indent
+ len(rep
),
169 allowance
+ 1, context
, level
)
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
184 def __repr(self
, object, context
, level
):
185 repr, readable
= _safe_repr(object, context
, self
.__depth
, level
)
191 def _safe_repr(object, context
, maxlevels
=None, level
=0):
194 if not (typ
in (DictType
, ListType
, TupleType
) and object):
196 return rep
, (rep
and (rep
[0] != '<'))
197 if context
.has_key(id(object)):
198 return `
_Recursion(object)`
, 0
203 if maxlevels
and level
>= maxlevels
:
207 items
= object.items()
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
)
220 s
, term
= (typ
is ListType
) and ('[', ']') or ('(', ')')
221 if maxlevels
and level
>= maxlevels
:
225 subrepr
, subreadable
= _safe_repr(
226 object[0], context
, maxlevels
, level
)
227 readable
= readable
and subreadable
234 subrepr
, subreadable
= _safe_repr(
235 ent
, context
, maxlevels
, level
)
236 readable
= readable
and subreadable
237 s
= "%s, %s" % (s
, subrepr
)
244 # represent a recursive relationship; really only used for the __repr__()
246 def __init__(self
, object):
247 self
.__repr
= "<Recursion on %s with id=%s>" \
248 % (type(object).__name
__, id(object))