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 io
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
:
139 r
= getattr(typ
, "__repr__", None)
140 if issubclass(typ
, dict) and r
is dict.__repr
__:
142 if self
._indent
_per
_level
> 1:
143 write((self
._indent
_per
_level
- 1) * ' ')
144 length
= _len(object)
147 indent
= indent
+ self
._indent
_per
_level
148 items
= sorted(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
)
158 write(',\n%s%s: ' % (' '*indent
, rep
))
159 self
._format
(ent
, stream
, indent
+ _len(rep
) + 2,
160 allowance
+ 1, context
, level
)
161 indent
= indent
- self
._indent
_per
_level
166 if ((issubclass(typ
, list) and r
is list.__repr
__) or
167 (issubclass(typ
, tuple) and r
is tuple.__repr
__) or
168 (issubclass(typ
, set) and r
is set.__repr
__) or
169 (issubclass(typ
, frozenset) and r
is frozenset.__repr
__)
171 length
= _len(object)
172 if issubclass(typ
, list):
175 elif issubclass(typ
, set):
181 object = sorted(object)
182 elif issubclass(typ
, frozenset):
188 object = sorted(object)
193 if self
._indent
_per
_level
> 1:
194 write((self
._indent
_per
_level
- 1) * ' ')
197 indent
= indent
+ self
._indent
_per
_level
198 self
._format
(object[0], stream
, indent
, allowance
+ 1,
201 for ent
in object[1:]:
202 write(',\n' + ' '*indent
)
203 self
._format
(ent
, stream
, indent
,
204 allowance
+ 1, context
, level
)
205 indent
= indent
- self
._indent
_per
_level
207 if issubclass(typ
, tuple) and length
== 1:
214 def _repr(self
, object, context
, level
):
215 repr, readable
, recursive
= self
.format(object, context
.copy(),
218 self
._readable
= False
220 self
._recursive
= True
223 def format(self
, object, context
, maxlevels
, level
):
224 """Format object for a specific context, returning a string
225 and flags indicating whether the representation is 'readable'
226 and whether the object represents a recursive construct.
228 return _safe_repr(object, context
, maxlevels
, level
)
231 # Return triple (repr_string, isreadable, isrecursive).
233 def _safe_repr(object, context
, maxlevels
, level
):
236 if 'locale' not in _sys
.modules
:
237 return repr(object), True, False
238 if "'" in object and '"' not in object:
240 quotes
= {'"': '\\"'}
243 quotes
= {"'": "\\'"}
251 write(qget(char
, repr(char
)[1:-1]))
252 return ("%s%s%s" % (closure
, sio
.getvalue(), closure
)), True, False
254 r
= getattr(typ
, "__repr__", None)
255 if issubclass(typ
, dict) and r
is dict.__repr
__:
257 return "{}", True, False
259 if maxlevels
and level
>= maxlevels
:
260 return "{...}", False, objid
in context
262 return _recursion(object), False, True
267 append
= components
.append
269 saferepr
= _safe_repr
270 items
= object.items()
272 items
= sorted(items
)
276 return str(type(key
)), key
, value
277 items
= sorted(items
, key
=sortkey
)
279 krepr
, kreadable
, krecur
= saferepr(k
, context
, maxlevels
, level
)
280 vrepr
, vreadable
, vrecur
= saferepr(v
, context
, maxlevels
, level
)
281 append("%s: %s" % (krepr
, vrepr
))
282 readable
= readable
and kreadable
and vreadable
286 return "{%s}" % _commajoin(components
), readable
, recursive
288 if (issubclass(typ
, list) and r
is list.__repr
__) or \
289 (issubclass(typ
, tuple) and r
is tuple.__repr
__):
290 if issubclass(typ
, list):
292 return "[]", True, False
294 elif _len(object) == 1:
298 return "()", True, False
301 if maxlevels
and level
>= maxlevels
:
302 return format
% "...", False, objid
in context
304 return _recursion(object), False, True
309 append
= components
.append
312 orepr
, oreadable
, orecur
= _safe_repr(o
, context
, maxlevels
, level
)
319 return format
% _commajoin(components
), readable
, recursive
322 return rep
, (rep
and not rep
.startswith('<')), False
325 def _recursion(object):
326 return ("<Recursion on %s with id=%s>"
327 % (_type(object).__name
__, _id(object)))
330 def _perfcheck(object=None):
333 object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
336 _safe_repr(object, {}, None, 0)
340 print("_safe_repr:", t2
- t1
)
341 print("pformat:", t3
- t2
)
343 if __name__
== "__main__":