| Guido van Rossum | 45e2fbc | 1998-03-26 21:13:24 +0000 | [diff] [blame] | 1 | #  Author:      Fred L. Drake, Jr. | 
 | 2 | #               fdrake@cnri.reston.va.us, fdrake@acm.org | 
| Guido van Rossum | 5e92aff | 1997-04-16 00:49:59 +0000 | [diff] [blame] | 3 | # | 
 | 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 | 
| Thomas Wouters | 7e47402 | 2000-07-16 12:04:32 +0000 | [diff] [blame] | 7 | #  tuples with fairly non-descriptive content.  This is modeled very much | 
| Guido van Rossum | 5e92aff | 1997-04-16 00:49:59 +0000 | [diff] [blame] | 8 | #  after Lisp/Scheme - style pretty-printing of lists.  If you find it | 
 | 9 | #  useful, thank small children who sleep at night. | 
 | 10 |  | 
 | 11 | """Support to pretty-print lists, tuples, & dictionaries recursively. | 
 | 12 |  | 
 | 13 | Very simple, but useful, especially in debugging data structures. | 
 | 14 |  | 
| Fred Drake | a89fda0 | 1997-04-16 16:59:30 +0000 | [diff] [blame] | 15 | Classes | 
 | 16 | ------- | 
 | 17 |  | 
 | 18 | PrettyPrinter() | 
 | 19 |     Handle pretty-printing operations onto a stream using a configured | 
 | 20 |     set of formatting parameters. | 
 | 21 |  | 
| Guido van Rossum | 5e92aff | 1997-04-16 00:49:59 +0000 | [diff] [blame] | 22 | Functions | 
 | 23 | --------- | 
 | 24 |  | 
 | 25 | pformat() | 
 | 26 |     Format a Python object into a pretty-printed representation. | 
 | 27 |  | 
 | 28 | pprint() | 
| Fred Drake | a89fda0 | 1997-04-16 16:59:30 +0000 | [diff] [blame] | 29 |     Pretty-print a Python object to a stream [default is sys.sydout]. | 
| Guido van Rossum | 5e92aff | 1997-04-16 00:49:59 +0000 | [diff] [blame] | 30 |  | 
| Fred Drake | a89fda0 | 1997-04-16 16:59:30 +0000 | [diff] [blame] | 31 | saferepr() | 
 | 32 |     Generate a 'standard' repr()-like value, but protect against recursive | 
 | 33 |     data structures. | 
| Guido van Rossum | 5e92aff | 1997-04-16 00:49:59 +0000 | [diff] [blame] | 34 |  | 
 | 35 | """ | 
 | 36 |  | 
| Guido van Rossum | 5e92aff | 1997-04-16 00:49:59 +0000 | [diff] [blame] | 37 | from types import DictType, ListType, TupleType | 
 | 38 |  | 
| Fred Drake | a89fda0 | 1997-04-16 16:59:30 +0000 | [diff] [blame] | 39 | try: | 
 | 40 |     from cStringIO import StringIO | 
 | 41 | except ImportError: | 
 | 42 |     from StringIO import StringIO | 
| Guido van Rossum | 5e92aff | 1997-04-16 00:49:59 +0000 | [diff] [blame] | 43 |  | 
 | 44 |  | 
| Fred Drake | a89fda0 | 1997-04-16 16:59:30 +0000 | [diff] [blame] | 45 | def pprint(object, stream=None): | 
 | 46 |     """Pretty-print a Python object to a stream [default is sys.sydout].""" | 
 | 47 |     printer = PrettyPrinter(stream=stream) | 
 | 48 |     printer.pprint(object) | 
| Guido van Rossum | 5e92aff | 1997-04-16 00:49:59 +0000 | [diff] [blame] | 49 |  | 
| Guido van Rossum | 5e92aff | 1997-04-16 00:49:59 +0000 | [diff] [blame] | 50 |  | 
| Fred Drake | a89fda0 | 1997-04-16 16:59:30 +0000 | [diff] [blame] | 51 | def pformat(object): | 
 | 52 |     """Format a Python object into a pretty-printed representation.""" | 
 | 53 |     return PrettyPrinter().pformat(object) | 
| Guido van Rossum | 5e92aff | 1997-04-16 00:49:59 +0000 | [diff] [blame] | 54 |  | 
| Guido van Rossum | 5e92aff | 1997-04-16 00:49:59 +0000 | [diff] [blame] | 55 |  | 
| Fred Drake | e0ffabe | 1997-07-18 20:42:39 +0000 | [diff] [blame] | 56 | def isreadable(object): | 
 | 57 |     """Determine if saferepr(object) is readable by eval().""" | 
 | 58 |     return PrettyPrinter().isreadable(object) | 
 | 59 |  | 
 | 60 |  | 
 | 61 | def isrecursive(object): | 
 | 62 |     """Determine if object requires a recursive representation.""" | 
 | 63 |     return PrettyPrinter().isrecursive(object) | 
 | 64 |  | 
 | 65 |  | 
| Fred Drake | a89fda0 | 1997-04-16 16:59:30 +0000 | [diff] [blame] | 66 | def saferepr(object): | 
 | 67 |     """Version of repr() which can handle recursive data structures.""" | 
| Fred Drake | e0ffabe | 1997-07-18 20:42:39 +0000 | [diff] [blame] | 68 |     return _safe_repr(object, {})[0] | 
| Guido van Rossum | 5e92aff | 1997-04-16 00:49:59 +0000 | [diff] [blame] | 69 |  | 
| Guido van Rossum | 5e92aff | 1997-04-16 00:49:59 +0000 | [diff] [blame] | 70 |  | 
| Fred Drake | a89fda0 | 1997-04-16 16:59:30 +0000 | [diff] [blame] | 71 | class PrettyPrinter: | 
 | 72 |     def __init__(self, indent=1, width=80, depth=None, stream=None): | 
| Guido van Rossum | 45e2fbc | 1998-03-26 21:13:24 +0000 | [diff] [blame] | 73 |         """Handle pretty printing operations onto a stream using a set of | 
 | 74 |         configured parameters. | 
| Guido van Rossum | 5e92aff | 1997-04-16 00:49:59 +0000 | [diff] [blame] | 75 |  | 
| Guido van Rossum | 45e2fbc | 1998-03-26 21:13:24 +0000 | [diff] [blame] | 76 |         indent | 
 | 77 |             Number of spaces to indent for each level of nesting. | 
| Guido van Rossum | 5e92aff | 1997-04-16 00:49:59 +0000 | [diff] [blame] | 78 |  | 
| Guido van Rossum | 45e2fbc | 1998-03-26 21:13:24 +0000 | [diff] [blame] | 79 |         width | 
 | 80 |             Attempted maximum number of columns in the output. | 
| Guido van Rossum | 5e92aff | 1997-04-16 00:49:59 +0000 | [diff] [blame] | 81 |  | 
| Guido van Rossum | 45e2fbc | 1998-03-26 21:13:24 +0000 | [diff] [blame] | 82 |         depth | 
 | 83 |             The maximum depth to print out nested structures. | 
| Guido van Rossum | 5e92aff | 1997-04-16 00:49:59 +0000 | [diff] [blame] | 84 |  | 
| Guido van Rossum | 45e2fbc | 1998-03-26 21:13:24 +0000 | [diff] [blame] | 85 |         stream | 
 | 86 |             The desired output stream.  If omitted (or false), the standard | 
 | 87 |             output stream available at construction will be used. | 
| Guido van Rossum | 5e92aff | 1997-04-16 00:49:59 +0000 | [diff] [blame] | 88 |  | 
| Guido van Rossum | 45e2fbc | 1998-03-26 21:13:24 +0000 | [diff] [blame] | 89 |         """ | 
 | 90 |         indent = int(indent) | 
 | 91 |         width = int(width) | 
 | 92 |         assert indent >= 0 | 
 | 93 |         assert (not depth) or depth > 0, "depth may not be negative" | 
 | 94 |         assert width | 
 | 95 |         self.__depth = depth | 
 | 96 |         self.__indent_per_level = indent | 
 | 97 |         self.__width = width | 
 | 98 |         if stream: | 
 | 99 |             self.__stream = stream | 
 | 100 |         else: | 
 | 101 |             import sys | 
 | 102 |             self.__stream = sys.stdout | 
| Guido van Rossum | 5e92aff | 1997-04-16 00:49:59 +0000 | [diff] [blame] | 103 |  | 
| Fred Drake | a89fda0 | 1997-04-16 16:59:30 +0000 | [diff] [blame] | 104 |     def pprint(self, object): | 
| Guido van Rossum | 45e2fbc | 1998-03-26 21:13:24 +0000 | [diff] [blame] | 105 |         self.__stream.write(self.pformat(object) + "\n") | 
| Fred Drake | a89fda0 | 1997-04-16 16:59:30 +0000 | [diff] [blame] | 106 |  | 
 | 107 |     def pformat(self, object): | 
| Guido van Rossum | 45e2fbc | 1998-03-26 21:13:24 +0000 | [diff] [blame] | 108 |         sio = StringIO() | 
 | 109 |         self.__format(object, sio, 0, 0, {}, 0) | 
 | 110 |         return sio.getvalue() | 
| Fred Drake | a89fda0 | 1997-04-16 16:59:30 +0000 | [diff] [blame] | 111 |  | 
| Fred Drake | e0ffabe | 1997-07-18 20:42:39 +0000 | [diff] [blame] | 112 |     def isrecursive(self, object): | 
| Guido van Rossum | 45e2fbc | 1998-03-26 21:13:24 +0000 | [diff] [blame] | 113 |         self.__recursive = 0 | 
 | 114 |         self.pformat(object) | 
 | 115 |         return self.__recursive | 
| Fred Drake | e0ffabe | 1997-07-18 20:42:39 +0000 | [diff] [blame] | 116 |  | 
 | 117 |     def isreadable(self, object): | 
| Guido van Rossum | 45e2fbc | 1998-03-26 21:13:24 +0000 | [diff] [blame] | 118 |         self.__recursive = 0 | 
 | 119 |         self.__readable = 1 | 
 | 120 |         self.pformat(object) | 
 | 121 |         return self.__readable and not self.__recursive | 
| Fred Drake | e0ffabe | 1997-07-18 20:42:39 +0000 | [diff] [blame] | 122 |  | 
| Fred Drake | a89fda0 | 1997-04-16 16:59:30 +0000 | [diff] [blame] | 123 |     def __format(self, object, stream, indent, allowance, context, level): | 
| Guido van Rossum | 45e2fbc | 1998-03-26 21:13:24 +0000 | [diff] [blame] | 124 |         level = level + 1 | 
 | 125 |         if context.has_key(id(object)): | 
 | 126 |             object = _Recursion(object) | 
 | 127 |             self.__recursive = 1 | 
 | 128 |         rep = self.__repr(object, context, level - 1) | 
 | 129 |         objid = id(object) | 
 | 130 |         context[objid] = 1 | 
 | 131 |         typ = type(object) | 
 | 132 |         sepLines = len(rep) > (self.__width - 1 - indent - allowance) | 
| Fred Drake | a89fda0 | 1997-04-16 16:59:30 +0000 | [diff] [blame] | 133 |  | 
| Guido van Rossum | 45e2fbc | 1998-03-26 21:13:24 +0000 | [diff] [blame] | 134 |         if sepLines and typ in (ListType, TupleType): | 
 | 135 |             #  Pretty-print the sequence. | 
 | 136 |             stream.write((typ is ListType) and '[' or '(') | 
 | 137 |             if self.__indent_per_level > 1: | 
 | 138 |                 stream.write((self.__indent_per_level - 1) * ' ') | 
 | 139 |             length = len(object) | 
 | 140 |             if length: | 
 | 141 |                 indent = indent + self.__indent_per_level | 
 | 142 |                 self.__format(object[0], stream, indent, allowance + 1, | 
 | 143 |                               context, level) | 
| Fred Drake | fbff97a | 1999-12-22 21:52:32 +0000 | [diff] [blame] | 144 |                 if length > 1: | 
| Guido van Rossum | 45e2fbc | 1998-03-26 21:13:24 +0000 | [diff] [blame] | 145 |                     for ent in object[1:]: | 
 | 146 |                         stream.write(',\n' + ' '*indent) | 
 | 147 |                         self.__format(ent, stream, indent, | 
 | 148 |                                       allowance + 1, context, level) | 
 | 149 |                 indent = indent - self.__indent_per_level | 
 | 150 |             if typ is TupleType and length == 1: | 
 | 151 |                 stream.write(',') | 
 | 152 |             stream.write(((typ is ListType) and ']') or ')') | 
| Fred Drake | a89fda0 | 1997-04-16 16:59:30 +0000 | [diff] [blame] | 153 |  | 
| Guido van Rossum | 45e2fbc | 1998-03-26 21:13:24 +0000 | [diff] [blame] | 154 |         elif sepLines and typ is DictType: | 
 | 155 |             stream.write('{') | 
 | 156 |             if self.__indent_per_level > 1: | 
 | 157 |                 stream.write((self.__indent_per_level - 1) * ' ') | 
 | 158 |             length = len(object) | 
 | 159 |             if length: | 
 | 160 |                 indent = indent + self.__indent_per_level | 
 | 161 |                 items  = object.items() | 
 | 162 |                 items.sort() | 
 | 163 |                 key, ent = items[0] | 
 | 164 |                 rep = self.__repr(key, context, level) + ': ' | 
 | 165 |                 stream.write(rep) | 
 | 166 |                 self.__format(ent, stream, indent + len(rep), | 
 | 167 |                               allowance + 1, context, level) | 
 | 168 |                 if len(items) > 1: | 
 | 169 |                     for key, ent in items[1:]: | 
 | 170 |                         rep = self.__repr(key, context, level) + ': ' | 
 | 171 |                         stream.write(',\n' + ' '*indent + rep) | 
 | 172 |                         self.__format(ent, stream, indent + len(rep), | 
 | 173 |                                       allowance + 1, context, level) | 
 | 174 |                 indent = indent - self.__indent_per_level | 
 | 175 |             stream.write('}') | 
| Fred Drake | a89fda0 | 1997-04-16 16:59:30 +0000 | [diff] [blame] | 176 |  | 
| Guido van Rossum | 45e2fbc | 1998-03-26 21:13:24 +0000 | [diff] [blame] | 177 |         else: | 
 | 178 |             stream.write(rep) | 
| Guido van Rossum | 183fd40 | 1999-09-02 15:09:44 +0000 | [diff] [blame] | 179 |  | 
 | 180 |         del context[objid] | 
| Guido van Rossum | 5e92aff | 1997-04-16 00:49:59 +0000 | [diff] [blame] | 181 |  | 
| Fred Drake | a89fda0 | 1997-04-16 16:59:30 +0000 | [diff] [blame] | 182 |     def __repr(self, object, context, level): | 
| Guido van Rossum | 45e2fbc | 1998-03-26 21:13:24 +0000 | [diff] [blame] | 183 |         repr, readable = _safe_repr(object, context, self.__depth, level) | 
 | 184 |         if not readable: | 
 | 185 |             self.__readable = 0 | 
 | 186 |         return repr | 
| Guido van Rossum | 5e92aff | 1997-04-16 00:49:59 +0000 | [diff] [blame] | 187 |  | 
| Guido van Rossum | 5e92aff | 1997-04-16 00:49:59 +0000 | [diff] [blame] | 188 |  | 
| Fred Drake | f39d051 | 1997-04-16 18:55:58 +0000 | [diff] [blame] | 189 | def _safe_repr(object, context, maxlevels=None, level=0): | 
| Fred Drake | a89fda0 | 1997-04-16 16:59:30 +0000 | [diff] [blame] | 190 |     level = level + 1 | 
 | 191 |     typ = type(object) | 
 | 192 |     if not (typ in (DictType, ListType, TupleType) and object): | 
| Guido van Rossum | 45e2fbc | 1998-03-26 21:13:24 +0000 | [diff] [blame] | 193 |         rep = `object` | 
| Fred Drake | d804f4e | 1999-02-17 17:30:52 +0000 | [diff] [blame] | 194 |         return rep, (rep and (rep[0] != '<')) | 
| Fred Drake | f39d051 | 1997-04-16 18:55:58 +0000 | [diff] [blame] | 195 |     if context.has_key(id(object)): | 
| Guido van Rossum | 45e2fbc | 1998-03-26 21:13:24 +0000 | [diff] [blame] | 196 |         return `_Recursion(object)`, 0 | 
| Fred Drake | a89fda0 | 1997-04-16 16:59:30 +0000 | [diff] [blame] | 197 |     objid = id(object) | 
 | 198 |     context[objid] = 1 | 
| Fred Drake | d804f4e | 1999-02-17 17:30:52 +0000 | [diff] [blame] | 199 |     readable = 1 | 
| Fred Drake | a89fda0 | 1997-04-16 16:59:30 +0000 | [diff] [blame] | 200 |     if typ is DictType: | 
| Guido van Rossum | 45e2fbc | 1998-03-26 21:13:24 +0000 | [diff] [blame] | 201 |         if maxlevels and level >= maxlevels: | 
 | 202 |             s = "{...}" | 
 | 203 |             readable = 0 | 
 | 204 |         else: | 
 | 205 |             items = object.items() | 
 | 206 |             k, v = items[0] | 
 | 207 |             krepr, kreadable = _safe_repr(k, context, maxlevels, level) | 
 | 208 |             vrepr, vreadable = _safe_repr(v, context, maxlevels, level) | 
 | 209 |             readable = readable and kreadable and vreadable | 
 | 210 |             s = "{%s: %s" % (krepr, vrepr) | 
 | 211 |             for k, v in items[1:]: | 
 | 212 |                 krepr, kreadable = _safe_repr(k, context, maxlevels, level) | 
 | 213 |                 vrepr, vreadable = _safe_repr(v, context, maxlevels, level) | 
 | 214 |                 readable = readable and kreadable and vreadable | 
 | 215 |                 s = "%s, %s: %s" % (s, krepr, vrepr) | 
 | 216 |             s = s + "}" | 
| Fred Drake | a89fda0 | 1997-04-16 16:59:30 +0000 | [diff] [blame] | 217 |     else: | 
| Guido van Rossum | 45e2fbc | 1998-03-26 21:13:24 +0000 | [diff] [blame] | 218 |         s, term = (typ is ListType) and ('[', ']') or ('(', ')') | 
 | 219 |         if maxlevels and level >= maxlevels: | 
 | 220 |             s = s + "..." | 
 | 221 |             readable = 0 | 
 | 222 |         else: | 
 | 223 |             subrepr, subreadable = _safe_repr( | 
 | 224 |                 object[0], context, maxlevels, level) | 
 | 225 |             readable = readable and subreadable | 
 | 226 |             s = s + subrepr | 
 | 227 |             tail = object[1:] | 
 | 228 |             if not tail: | 
 | 229 |                 if typ is TupleType: | 
 | 230 |                     s = s + ',' | 
 | 231 |             for ent in tail: | 
 | 232 |                 subrepr, subreadable = _safe_repr( | 
 | 233 |                     ent, context, maxlevels, level) | 
 | 234 |                 readable = readable and subreadable | 
 | 235 |                 s = "%s, %s" % (s, subrepr) | 
 | 236 |         s = s + term | 
| Fred Drake | a89fda0 | 1997-04-16 16:59:30 +0000 | [diff] [blame] | 237 |     del context[objid] | 
| Fred Drake | e0ffabe | 1997-07-18 20:42:39 +0000 | [diff] [blame] | 238 |     return s, readable | 
| Guido van Rossum | 5e92aff | 1997-04-16 00:49:59 +0000 | [diff] [blame] | 239 |  | 
| Fred Drake | a89fda0 | 1997-04-16 16:59:30 +0000 | [diff] [blame] | 240 |  | 
 | 241 | class _Recursion: | 
 | 242 |     # represent a recursive relationship; really only used for the __repr__() | 
 | 243 |     # method... | 
 | 244 |     def __init__(self, object): | 
| Guido van Rossum | 45e2fbc | 1998-03-26 21:13:24 +0000 | [diff] [blame] | 245 |         self.__repr = "<Recursion on %s with id=%s>" \ | 
 | 246 |                       % (type(object).__name__, id(object)) | 
| Fred Drake | a89fda0 | 1997-04-16 16:59:30 +0000 | [diff] [blame] | 247 |  | 
 | 248 |     def __repr__(self): | 
| Guido van Rossum | 45e2fbc | 1998-03-26 21:13:24 +0000 | [diff] [blame] | 249 |         return self.__repr |