blob: 850b0f7384ce0566768b0255200271696c5f772a [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 Drakea89fda01997-04-16 16:59:30 +0000156def _safe_repr(object, context=None, maxlevels=None, level=0):
157 level = level + 1
158 typ = type(object)
159 if not (typ in (DictType, ListType, TupleType) and object):
160 return `object`
161 if context is None:
162 context = {}
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000163 else:
Fred Drakea89fda01997-04-16 16:59:30 +0000164 if context.has_key(id(object)):
165 return `_Recursion(object)`
166 objid = id(object)
167 context[objid] = 1
168 if typ is DictType:
169 if maxlevels and level >= maxlevels:
170 s = "{...}"
171 else:
172 items = object.items()
173 k, v = items[0]
174 s = "{%s: %s" % (_safe_repr(k, context), _safe_repr(v, context))
175 for k, v in items[1:]:
176 s = "%s, %s: %s" \
177 % (s, _safe_repr(k, context), _safe_repr(v, context))
178 s = s + "}"
179 else:
180 s, term = (typ is ListType) and ('[', ']') or ('(', ')')
181 if maxlevels and level >= maxlevels:
182 s = s + "..."
183 else:
184 s = s + _safe_repr(object[0], context)
185 for ent in object[1:]:
186 s = "%s, %s" % (s, _safe_repr(ent, context))
187 s = s + term
188 del context[objid]
189 return s
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000190
Fred Drakea89fda01997-04-16 16:59:30 +0000191
192class _Recursion:
193 # represent a recursive relationship; really only used for the __repr__()
194 # method...
195 def __init__(self, object):
196 self.__repr = "<Recursion on %s with id=%s>" \
197 % (type(object).__name__, id(object))
198
199 def __repr__(self):
200 return self.__repr