1 # Author: Fred L. Drake, Jr.
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
, StringType
41 from cStringIO
import StringIO
43 from StringIO
import StringIO
45 __all__
= ["pprint","pformat","isreadable","isrecursive","saferepr",
48 # cache these for faster access:
49 _commajoin
= ", ".join
50 _sys_modules
= sys
.modules
56 def pprint(object, stream
=None):
57 """Pretty-print a Python object to a stream [default is sys.sydout]."""
58 printer
= PrettyPrinter(stream
=stream
)
59 printer
.pprint(object)
62 """Format a Python object into a pretty-printed representation."""
63 return PrettyPrinter().pformat(object)
66 """Version of repr() which can handle recursive data structures."""
67 return _safe_repr(object, {}, None, 0)[0]
69 def isreadable(object):
70 """Determine if saferepr(object) is readable by eval()."""
71 return _safe_repr(object, {}, None, 0)[1]
73 def isrecursive(object):
74 """Determine if object requires a recursive representation."""
75 return _safe_repr(object, {}, None, 0)[2]
78 def __init__(self
, indent
=1, width
=80, depth
=None, stream
=None):
79 """Handle pretty printing operations onto a stream using a set of
80 configured parameters.
83 Number of spaces to indent for each level of nesting.
86 Attempted maximum number of columns in the output.
89 The maximum depth to print out nested structures.
92 The desired output stream. If omitted (or false), the standard
93 output stream available at construction will be used.
99 assert depth
is None or depth
> 0, "depth must be > 0"
102 self
._indent
_per
_level
= indent
104 if stream
is not None:
105 self
._stream
= stream
107 self
._stream
= sys
.stdout
109 def pprint(self
, object):
110 self
._stream
.write(self
.pformat(object) + "\n")
112 def pformat(self
, object):
114 self
._format
(object, sio
, 0, 0, {}, 0)
115 return sio
.getvalue()
117 def isrecursive(self
, object):
118 return self
.format(object, {}, 0)[2]
120 def isreadable(self
, object):
121 s
, readable
, recursive
= self
.format(object, {}, 0)
122 return readable
and not recursive
124 def _format(self
, object, stream
, indent
, allowance
, context
, level
):
128 stream
.write(_recursion(object))
129 self
._recursive
= True
130 self
._readable
= False
132 rep
= self
._repr
(object, context
, level
- 1)
134 sepLines
= _len(rep
) > (self
._width
- 1 - indent
- allowance
)
140 if self
._indent
_per
_level
> 1:
141 write((self
._indent
_per
_level
- 1) * ' ')
142 length
= _len(object)
145 indent
= indent
+ self
._indent
_per
_level
146 items
= object.items()
149 rep
= self
._repr
(key
, context
, level
)
152 self
._format
(ent
, stream
, indent
+ _len(rep
) + 2,
153 allowance
+ 1, context
, level
)
155 for key
, ent
in items
[1:]:
156 rep
= self
._repr
(key
, context
, level
)
157 write(',\n%s%s: ' % (' '*indent
, rep
))
158 self
._format
(ent
, stream
, indent
+ _len(rep
) + 2,
159 allowance
+ 1, context
, level
)
160 indent
= indent
- self
._indent
_per
_level
165 if typ
is ListType
or typ
is TupleType
:
172 if self
._indent
_per
_level
> 1:
173 write((self
._indent
_per
_level
- 1) * ' ')
174 length
= _len(object)
177 indent
= indent
+ self
._indent
_per
_level
178 self
._format
(object[0], stream
, indent
, allowance
+ 1,
181 for ent
in object[1:]:
182 write(',\n' + ' '*indent
)
183 self
._format
(ent
, stream
, indent
,
184 allowance
+ 1, context
, level
)
185 indent
= indent
- self
._indent
_per
_level
187 if typ
is TupleType
and length
== 1:
194 def _repr(self
, object, context
, level
):
195 repr, readable
, recursive
= self
.format(object, context
.copy(),
198 self
._readable
= False
200 self
._recursive
= True
203 def format(self
, object, context
, maxlevels
, level
):
204 """Format object for a specific context, returning a string
205 and flags indicating whether the representation is 'readable'
206 and whether the object represents a recursive construct.
208 return _safe_repr(object, context
, maxlevels
, level
)
211 # Return triple (repr_string, isreadable, isrecursive).
213 def _safe_repr(object, context
, maxlevels
, level
):
215 if typ
is StringType
:
216 if 'locale' not in _sys_modules
:
217 return `
object`
, True, False
218 if "'" in object and '"' not in object:
220 quotes
= {'"': '\\"'}
223 quotes
= {"'": "\\'"}
231 write(qget(char
, `char`
[1:-1]))
232 return ("%s%s%s" % (closure
, sio
.getvalue(), closure
)), True, False
236 return "{}", True, False
238 if maxlevels
and level
> maxlevels
:
239 return "{...}", False, objid
in context
241 return _recursion(object), False, True
246 append
= components
.append
248 saferepr
= _safe_repr
249 for k
, v
in object.iteritems():
250 krepr
, kreadable
, krecur
= saferepr(k
, context
, maxlevels
, level
)
251 vrepr
, vreadable
, vrecur
= saferepr(v
, context
, maxlevels
, level
)
252 append("%s: %s" % (krepr
, vrepr
))
253 readable
= readable
and kreadable
and vreadable
257 return "{%s}" % _commajoin(components
), readable
, recursive
259 if typ
is ListType
or typ
is TupleType
:
262 return "[]", True, False
264 elif _len(object) == 1:
268 return "()", True, False
271 if maxlevels
and level
> maxlevels
:
272 return format
% "...", False, objid
in context
274 return _recursion(object), False, True
279 append
= components
.append
282 orepr
, oreadable
, orecur
= _safe_repr(o
, context
, maxlevels
, level
)
289 return format
% _commajoin(components
), readable
, recursive
292 return rep
, (rep
and not rep
.startswith('<')), False
295 def _recursion(object):
296 return ("<Recursion on %s with id=%s>"
297 % (_type(object).__name
__, _id(object)))
300 def _perfcheck(object=None):
303 object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
306 _safe_repr(object, {}, None, 0)
310 print "_safe_repr:", t2
- t1
311 print "pformat:", t3
- t2
313 if __name__
== "__main__":