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.stdout].
32 Generate a 'standard' repr()-like value, but protect against recursive
39 from cStringIO
import StringIO
as _StringIO
41 __all__
= ["pprint","pformat","isreadable","isrecursive","saferepr",
44 # cache these for faster access:
45 _commajoin
= ", ".join
51 def pprint(object, stream
=None, indent
=1, width
=80, depth
=None):
52 """Pretty-print a Python object to a stream [default is sys.stdout]."""
53 printer
= PrettyPrinter(
54 stream
=stream
, indent
=indent
, width
=width
, depth
=depth
)
55 printer
.pprint(object)
57 def pformat(object, indent
=1, width
=80, depth
=None):
58 """Format a Python object into a pretty-printed representation."""
59 return PrettyPrinter(indent
=indent
, width
=width
, depth
=depth
).pformat(object)
62 """Version of repr() which can handle recursive data structures."""
63 return _safe_repr(object, {}, None, 0)[0]
65 def isreadable(object):
66 """Determine if saferepr(object) is readable by eval()."""
67 return _safe_repr(object, {}, None, 0)[1]
69 def isrecursive(object):
70 """Determine if object requires a recursive representation."""
71 return _safe_repr(object, {}, None, 0)[2]
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.
94 assert indent
>= 0, "indent must be >= 0"
95 assert depth
is None or depth
> 0, "depth must be > 0"
96 assert width
, "width must be != 0"
98 self
._indent
_per
_level
= indent
100 if stream
is not None:
101 self
._stream
= stream
103 self
._stream
= _sys
.stdout
105 def pprint(self
, object):
106 self
._format
(object, self
._stream
, 0, 0, {}, 0)
107 self
._stream
.write("\n")
109 def pformat(self
, object):
111 self
._format
(object, sio
, 0, 0, {}, 0)
112 return sio
.getvalue()
114 def isrecursive(self
, object):
115 return self
.format(object, {}, 0, 0)[2]
117 def isreadable(self
, object):
118 s
, readable
, recursive
= self
.format(object, {}, 0, 0)
119 return readable
and not recursive
121 def _format(self
, object, stream
, indent
, allowance
, context
, level
):
125 stream
.write(_recursion(object))
126 self
._recursive
= True
127 self
._readable
= False
129 rep
= self
._repr
(object, context
, level
- 1)
131 sepLines
= _len(rep
) > (self
._width
- 1 - indent
- allowance
)
134 if self
._depth
and level
> self
._depth
:
138 r
= getattr(typ
, "__repr__", None)
139 if issubclass(typ
, dict) and r
is dict.__repr
__:
141 if self
._indent
_per
_level
> 1:
142 write((self
._indent
_per
_level
- 1) * ' ')
143 length
= _len(object)
146 indent
= indent
+ self
._indent
_per
_level
147 items
= object.items()
150 rep
= self
._repr
(key
, context
, level
)
153 self
._format
(ent
, stream
, indent
+ _len(rep
) + 2,
154 allowance
+ 1, context
, level
)
156 for key
, ent
in items
[1:]:
157 rep
= self
._repr
(key
, context
, level
)
159 write(',\n%s%s: ' % (' '*indent
, rep
))
161 write(', %s: ' % rep
)
162 self
._format
(ent
, stream
, indent
+ _len(rep
) + 2,
163 allowance
+ 1, context
, level
)
164 indent
= indent
- self
._indent
_per
_level
169 if ((issubclass(typ
, list) and r
is list.__repr
__) or
170 (issubclass(typ
, tuple) and r
is tuple.__repr
__) or
171 (issubclass(typ
, set) and r
is set.__repr
__) or
172 (issubclass(typ
, frozenset) and r
is frozenset.__repr
__)
174 length
= _len(object)
175 if issubclass(typ
, list):
178 elif issubclass(typ
, set):
184 object = sorted(object)
186 elif issubclass(typ
, frozenset):
192 object = sorted(object)
197 if self
._indent
_per
_level
> 1 and sepLines
:
198 write((self
._indent
_per
_level
- 1) * ' ')
201 indent
= indent
+ self
._indent
_per
_level
202 self
._format
(object[0], stream
, indent
, allowance
+ 1,
205 for ent
in object[1:]:
207 write(',\n' + ' '*indent
)
210 self
._format
(ent
, stream
, indent
,
211 allowance
+ 1, context
, level
)
212 indent
= indent
- self
._indent
_per
_level
214 if issubclass(typ
, tuple) and length
== 1:
221 def _repr(self
, object, context
, level
):
222 repr, readable
, recursive
= self
.format(object, context
.copy(),
225 self
._readable
= False
227 self
._recursive
= True
230 def format(self
, object, context
, maxlevels
, level
):
231 """Format object for a specific context, returning a string
232 and flags indicating whether the representation is 'readable'
233 and whether the object represents a recursive construct.
235 return _safe_repr(object, context
, maxlevels
, level
)
238 # Return triple (repr_string, isreadable, isrecursive).
240 def _safe_repr(object, context
, maxlevels
, level
):
243 if 'locale' not in _sys
.modules
:
244 return repr(object), True, False
245 if "'" in object and '"' not in object:
247 quotes
= {'"': '\\"'}
250 quotes
= {"'": "\\'"}
258 write(qget(char
, repr(char
)[1:-1]))
259 return ("%s%s%s" % (closure
, sio
.getvalue(), closure
)), True, False
261 r
= getattr(typ
, "__repr__", None)
262 if issubclass(typ
, dict) and r
is dict.__repr
__:
264 return "{}", True, False
266 if maxlevels
and level
>= maxlevels
:
267 return "{...}", False, objid
in context
269 return _recursion(object), False, True
274 append
= components
.append
276 saferepr
= _safe_repr
277 for k
, v
in sorted(object.items()):
278 krepr
, kreadable
, krecur
= saferepr(k
, context
, maxlevels
, level
)
279 vrepr
, vreadable
, vrecur
= saferepr(v
, context
, maxlevels
, level
)
280 append("%s: %s" % (krepr
, vrepr
))
281 readable
= readable
and kreadable
and vreadable
285 return "{%s}" % _commajoin(components
), readable
, recursive
287 if (issubclass(typ
, list) and r
is list.__repr
__) or \
288 (issubclass(typ
, tuple) and r
is tuple.__repr
__):
289 if issubclass(typ
, list):
291 return "[]", True, False
293 elif _len(object) == 1:
297 return "()", True, False
300 if maxlevels
and level
>= maxlevels
:
301 return format
% "...", False, objid
in context
303 return _recursion(object), False, True
308 append
= components
.append
311 orepr
, oreadable
, orecur
= _safe_repr(o
, context
, maxlevels
, level
)
318 return format
% _commajoin(components
), readable
, recursive
321 return rep
, (rep
and not rep
.startswith('<')), False
324 def _recursion(object):
325 return ("<Recursion on %s with id=%s>"
326 % (_type(object).__name
__, _id(object)))
329 def _perfcheck(object=None):
332 object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
335 _safe_repr(object, {}, None, 0)
339 print "_safe_repr:", t2
- t1
340 print "pformat:", t3
- t2
342 if __name__
== "__main__":