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
40 from cStringIO
import StringIO
as _StringIO
42 __all__
= ["pprint","pformat","isreadable","isrecursive","saferepr",
45 # cache these for faster access:
46 _commajoin
= ", ".join
52 def pprint(object, stream
=None, indent
=1, width
=80, depth
=None):
53 """Pretty-print a Python object to a stream [default is sys.stdout]."""
54 printer
= PrettyPrinter(
55 stream
=stream
, indent
=indent
, width
=width
, depth
=depth
)
56 printer
.pprint(object)
58 def pformat(object, indent
=1, width
=80, depth
=None):
59 """Format a Python object into a pretty-printed representation."""
60 return PrettyPrinter(indent
=indent
, width
=width
, depth
=depth
).pformat(object)
63 """Version of repr() which can handle recursive data structures."""
64 return _safe_repr(object, {}, None, 0)[0]
66 def isreadable(object):
67 """Determine if saferepr(object) is readable by eval()."""
68 return _safe_repr(object, {}, None, 0)[1]
70 def isrecursive(object):
71 """Determine if object requires a recursive representation."""
72 return _safe_repr(object, {}, None, 0)[2]
74 def _sorted(iterable
):
75 with warnings
.catch_warnings():
77 warnings
.filterwarnings("ignore", "comparing unequal types "
78 "not supported", DeprecationWarning)
79 return sorted(iterable
)
82 def __init__(self
, indent
=1, width
=80, depth
=None, stream
=None):
83 """Handle pretty printing operations onto a stream using a set of
84 configured parameters.
87 Number of spaces to indent for each level of nesting.
90 Attempted maximum number of columns in the output.
93 The maximum depth to print out nested structures.
96 The desired output stream. If omitted (or false), the standard
97 output stream available at construction will be used.
102 assert indent
>= 0, "indent must be >= 0"
103 assert depth
is None or depth
> 0, "depth must be > 0"
104 assert width
, "width must be != 0"
106 self
._indent
_per
_level
= indent
108 if stream
is not None:
109 self
._stream
= stream
111 self
._stream
= _sys
.stdout
113 def pprint(self
, object):
114 self
._format
(object, self
._stream
, 0, 0, {}, 0)
115 self
._stream
.write("\n")
117 def pformat(self
, object):
119 self
._format
(object, sio
, 0, 0, {}, 0)
120 return sio
.getvalue()
122 def isrecursive(self
, object):
123 return self
.format(object, {}, 0, 0)[2]
125 def isreadable(self
, object):
126 s
, readable
, recursive
= self
.format(object, {}, 0, 0)
127 return readable
and not recursive
129 def _format(self
, object, stream
, indent
, allowance
, context
, level
):
133 stream
.write(_recursion(object))
134 self
._recursive
= True
135 self
._readable
= False
137 rep
= self
._repr
(object, context
, level
- 1)
139 sepLines
= _len(rep
) > (self
._width
- 1 - indent
- allowance
)
142 if self
._depth
and level
> self
._depth
:
146 r
= getattr(typ
, "__repr__", None)
147 if issubclass(typ
, dict) and r
is dict.__repr
__:
149 if self
._indent
_per
_level
> 1:
150 write((self
._indent
_per
_level
- 1) * ' ')
151 length
= _len(object)
154 indent
= indent
+ self
._indent
_per
_level
155 items
= _sorted(object.items())
157 rep
= self
._repr
(key
, context
, level
)
160 self
._format
(ent
, stream
, indent
+ _len(rep
) + 2,
161 allowance
+ 1, context
, level
)
163 for key
, ent
in items
[1:]:
164 rep
= self
._repr
(key
, context
, level
)
166 write(',\n%s%s: ' % (' '*indent
, rep
))
168 write(', %s: ' % rep
)
169 self
._format
(ent
, stream
, indent
+ _len(rep
) + 2,
170 allowance
+ 1, context
, level
)
171 indent
= indent
- self
._indent
_per
_level
176 if ((issubclass(typ
, list) and r
is list.__repr
__) or
177 (issubclass(typ
, tuple) and r
is tuple.__repr
__) or
178 (issubclass(typ
, set) and r
is set.__repr
__) or
179 (issubclass(typ
, frozenset) and r
is frozenset.__repr
__)
181 length
= _len(object)
182 if issubclass(typ
, list):
185 elif issubclass(typ
, set):
191 object = _sorted(object)
193 elif issubclass(typ
, frozenset):
199 object = _sorted(object)
204 if self
._indent
_per
_level
> 1 and sepLines
:
205 write((self
._indent
_per
_level
- 1) * ' ')
208 indent
= indent
+ self
._indent
_per
_level
209 self
._format
(object[0], stream
, indent
, allowance
+ 1,
212 for ent
in object[1:]:
214 write(',\n' + ' '*indent
)
217 self
._format
(ent
, stream
, indent
,
218 allowance
+ 1, context
, level
)
219 indent
= indent
- self
._indent
_per
_level
221 if issubclass(typ
, tuple) and length
== 1:
228 def _repr(self
, object, context
, level
):
229 repr, readable
, recursive
= self
.format(object, context
.copy(),
232 self
._readable
= False
234 self
._recursive
= True
237 def format(self
, object, context
, maxlevels
, level
):
238 """Format object for a specific context, returning a string
239 and flags indicating whether the representation is 'readable'
240 and whether the object represents a recursive construct.
242 return _safe_repr(object, context
, maxlevels
, level
)
245 # Return triple (repr_string, isreadable, isrecursive).
247 def _safe_repr(object, context
, maxlevels
, level
):
250 if 'locale' not in _sys
.modules
:
251 return repr(object), True, False
252 if "'" in object and '"' not in object:
254 quotes
= {'"': '\\"'}
257 quotes
= {"'": "\\'"}
265 write(qget(char
, repr(char
)[1:-1]))
266 return ("%s%s%s" % (closure
, sio
.getvalue(), closure
)), True, False
268 r
= getattr(typ
, "__repr__", None)
269 if issubclass(typ
, dict) and r
is dict.__repr
__:
271 return "{}", True, False
273 if maxlevels
and level
>= maxlevels
:
274 return "{...}", False, objid
in context
276 return _recursion(object), False, True
281 append
= components
.append
283 saferepr
= _safe_repr
284 for k
, v
in _sorted(object.items()):
285 krepr
, kreadable
, krecur
= saferepr(k
, context
, maxlevels
, level
)
286 vrepr
, vreadable
, vrecur
= saferepr(v
, context
, maxlevels
, level
)
287 append("%s: %s" % (krepr
, vrepr
))
288 readable
= readable
and kreadable
and vreadable
292 return "{%s}" % _commajoin(components
), readable
, recursive
294 if (issubclass(typ
, list) and r
is list.__repr
__) or \
295 (issubclass(typ
, tuple) and r
is tuple.__repr
__):
296 if issubclass(typ
, list):
298 return "[]", True, False
300 elif _len(object) == 1:
304 return "()", True, False
307 if maxlevels
and level
>= maxlevels
:
308 return format
% "...", False, objid
in context
310 return _recursion(object), False, True
315 append
= components
.append
318 orepr
, oreadable
, orecur
= _safe_repr(o
, context
, maxlevels
, level
)
325 return format
% _commajoin(components
), readable
, recursive
328 return rep
, (rep
and not rep
.startswith('<')), False
331 def _recursion(object):
332 return ("<Recursion on %s with id=%s>"
333 % (_type(object).__name
__, _id(object)))
336 def _perfcheck(object=None):
339 object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
342 _safe_repr(object, {}, None, 0)
346 print "_safe_repr:", t2
- t1
347 print "pformat:", t3
- t2
349 if __name__
== "__main__":