blob: a16edb350f43ce566ac124acad2ebf72736dc48e [file] [log] [blame]
Guido van Rossum5e92aff1997-04-16 00:49:59 +00001# pprint.py
2#
3# Author: Fred L. Drake, Jr.
Fred Drakea89fda01997-04-16 16:59:30 +00004# fdrake@cnri.reston.va.us, fdrake@acm.org
Guido van Rossum5e92aff1997-04-16 00:49:59 +00005#
6# This is a simple little module I wrote to make life easier. I didn't
7# see anything quite like it in the library, though I may have overlooked
8# something. I wrote this when I was trying to read some heavily nested
9# tuples with fairly non-descriptive content. This is modelled very much
10# after Lisp/Scheme - style pretty-printing of lists. If you find it
11# useful, thank small children who sleep at night.
12
13"""Support to pretty-print lists, tuples, & dictionaries recursively.
14
15Very simple, but useful, especially in debugging data structures.
16
Fred Drakea89fda01997-04-16 16:59:30 +000017Classes
18-------
19
20PrettyPrinter()
21 Handle pretty-printing operations onto a stream using a configured
22 set of formatting parameters.
23
Guido van Rossum5e92aff1997-04-16 00:49:59 +000024Functions
25---------
26
27pformat()
28 Format a Python object into a pretty-printed representation.
29
30pprint()
Fred Drakea89fda01997-04-16 16:59:30 +000031 Pretty-print a Python object to a stream [default is sys.sydout].
Guido van Rossum5e92aff1997-04-16 00:49:59 +000032
Fred Drakea89fda01997-04-16 16:59:30 +000033saferepr()
34 Generate a 'standard' repr()-like value, but protect against recursive
35 data structures.
Guido van Rossum5e92aff1997-04-16 00:49:59 +000036
37"""
38
Guido van Rossum5e92aff1997-04-16 00:49:59 +000039from types import DictType, ListType, TupleType
40
Fred Drakea89fda01997-04-16 16:59:30 +000041try:
42 from cStringIO import StringIO
43except ImportError:
44 from StringIO import StringIO
Guido van Rossum5e92aff1997-04-16 00:49:59 +000045
46
Fred Drakea89fda01997-04-16 16:59:30 +000047def 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)
Guido van Rossum5e92aff1997-04-16 00:49:59 +000051
Guido van Rossum5e92aff1997-04-16 00:49:59 +000052
Fred Drakea89fda01997-04-16 16:59:30 +000053def pformat(object):
54 """Format a Python object into a pretty-printed representation."""
55 return PrettyPrinter().pformat(object)
Guido van Rossum5e92aff1997-04-16 00:49:59 +000056
Guido van Rossum5e92aff1997-04-16 00:49:59 +000057
Fred Drakea89fda01997-04-16 16:59:30 +000058def saferepr(object):
59 """Version of repr() which can handle recursive data structures."""
60 return _safe_repr(object, {})
Guido van Rossum5e92aff1997-04-16 00:49:59 +000061
Guido van Rossum5e92aff1997-04-16 00:49:59 +000062
Fred Drakea89fda01997-04-16 16:59:30 +000063class PrettyPrinter:
64 def __init__(self, indent=1, width=80, depth=None, stream=None):
65 """Handle pretty printing operations onto a stream using a set of
66 configured parameters.
Guido van Rossum5e92aff1997-04-16 00:49:59 +000067
Fred Drakea89fda01997-04-16 16:59:30 +000068 indent
69 Number of spaces to indent for each level of nesting.
Guido van Rossum5e92aff1997-04-16 00:49:59 +000070
Fred Drakea89fda01997-04-16 16:59:30 +000071 width
72 Attempted maximum number of columns in the output.
Guido van Rossum5e92aff1997-04-16 00:49:59 +000073
Fred Drakea89fda01997-04-16 16:59:30 +000074 depth
75 The maximum depth to print out nested structures.
Guido van Rossum5e92aff1997-04-16 00:49:59 +000076
Fred Drakea89fda01997-04-16 16:59:30 +000077 stream
78 The desired output stream. If omitted (or false), the standard
79 output stream available at construction will be used.
Guido van Rossum5e92aff1997-04-16 00:49:59 +000080
Fred Drakea89fda01997-04-16 16:59:30 +000081 """
82 assert (not depth) or depth > 0, "depth may not be negative"
83 assert int(indent) or 1
84 assert int(width) or 1
85 self.__depth = depth
86 self.__indent_per_level = indent
87 self.__width = width
88 if stream:
89 self.__stream = stream
90 else:
91 import sys
92 self.__stream = sys.stdout
Guido van Rossum5e92aff1997-04-16 00:49:59 +000093
Fred Drakea89fda01997-04-16 16:59:30 +000094 def pprint(self, object):
95 self.__stream.write(self.pformat(object) + "\n")
96
97 def pformat(self, object):
98 sio = StringIO()
99 self.__format(object, sio, 0, 0, {}, 0)
100 return sio.getvalue()
101
102 def __format(self, object, stream, indent, allowance, context, level):
103 level = level + 1
104 if context.has_key(id(object)):
105 object = _Recursion(object)
106 rep = self__repr(object, context, level - 1)
107 objid = id(object)
108 context[objid] = 1
109 typ = type(object)
110 sepLines = len(rep) > (self.__width - 1 - indent - allowance)
111
112 if sepLines and typ in (ListType, TupleType):
113 # Pretty-print the sequence.
114 stream.write((typ is ListType) and '[' or '(')
115 length = len(object)
116 if length:
117 indent = indent + self.__indent_per_level
118 pprint(object[0], stream, indent, allowance + 1)
119 if len(object) > 1:
120 for ent in object[1:]:
121 stream.write(',\n' + ' '*indent)
122 self.__format(ent, stream, indent,
123 allowance + 1, context, level)
124 indent = indent - self.__indent_per_level
125 stream.write(((typ is ListType) and ']') or ')')
126
127 elif sepLines and typ is DictType:
128 stream.write('{')
129 length = len(object)
130 if length:
131 indent = indent + self.__indent_per_level
132 items = object.items()
133 items.sort()
134 key, ent = items[0]
135 rep = self.__repr(key, context, level) + ': '
136 stream.write(rep)
137 self.__format(ent, stream, indent + len(rep),
138 allowance + 1, context, level)
139 if len(items) > 1:
140 for key, ent in items[1:]:
141 rep = self.__repr(key, context, level) + ': '
142 stream.write(',\n' + ' '*indent + rep)
143 self.__format(ent, stream, indent + len(rep),
144 allowance + 1, context, level)
145 indent = indent - self.__indent_per_level
146 stream.write('}')
147
148 else:
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000149 stream.write(rep)
Fred Drakea89fda01997-04-16 16:59:30 +0000150 del context[objid]
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000151
Fred Drakea89fda01997-04-16 16:59:30 +0000152 def __repr(self, object, context, level):
153 return _safe_repr(object, context, self.__depth, level)
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000154
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000155
Fred Drakef39d0511997-04-16 18:55:58 +0000156def _safe_repr(object, context, maxlevels=None, level=0):
Fred Drakea89fda01997-04-16 16:59:30 +0000157 level = level + 1
158 typ = type(object)
159 if not (typ in (DictType, ListType, TupleType) and object):
160 return `object`
Fred Drakef39d0511997-04-16 18:55:58 +0000161 if context.has_key(id(object)):
162 return `_Recursion(object)`
Fred Drakea89fda01997-04-16 16:59:30 +0000163 objid = id(object)
164 context[objid] = 1
165 if typ is DictType:
166 if maxlevels and level >= maxlevels:
167 s = "{...}"
168 else:
169 items = object.items()
170 k, v = items[0]
Fred Drakef39d0511997-04-16 18:55:58 +0000171 s = "{%s: %s" % (_safe_repr(k, context, maxlevels, level),
172 _safe_repr(v, context, maxlevels, level))
Fred Drakea89fda01997-04-16 16:59:30 +0000173 for k, v in items[1:]:
174 s = "%s, %s: %s" \
Fred Drakef39d0511997-04-16 18:55:58 +0000175 % (s, _safe_repr(k, context, maxlevels, level),
176 _safe_repr(v, context, maxlevels, level))
Fred Drakea89fda01997-04-16 16:59:30 +0000177 s = s + "}"
178 else:
179 s, term = (typ is ListType) and ('[', ']') or ('(', ')')
180 if maxlevels and level >= maxlevels:
181 s = s + "..."
182 else:
Fred Drakef39d0511997-04-16 18:55:58 +0000183 s = s + _safe_repr(object[0], context, maxlevels, level)
Fred Drakea89fda01997-04-16 16:59:30 +0000184 for ent in object[1:]:
Fred Drakef39d0511997-04-16 18:55:58 +0000185 s = "%s, %s" % (s, _safe_repr(ent, context, maxlevels, level))
Fred Drakea89fda01997-04-16 16:59:30 +0000186 s = s + term
187 del context[objid]
188 return s
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000189
Fred Drakea89fda01997-04-16 16:59:30 +0000190
191class _Recursion:
192 # represent a recursive relationship; really only used for the __repr__()
193 # method...
194 def __init__(self, object):
195 self.__repr = "<Recursion on %s with id=%s>" \
196 % (type(object).__name__, id(object))
197
198 def __repr__(self):
199 return self.__repr