Guido van Rossum | 16d27e3 | 1996-08-21 16:28:53 +0000 | [diff] [blame^] | 1 | # pprint.py |
| 2 | # |
| 3 | # Author: Fred L. Drake, Jr. |
| 4 | # fdrake@vt.edu |
| 5 | # |
| 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 | |
| 14 | """Support to pretty-print lists, tuples, & dictionaries recursively. |
| 15 | Very simple, but at least somewhat useful, especially in debugging |
| 16 | data structures. |
| 17 | |
| 18 | INDENT_PER_LEVEL -- Amount of indentation to use for each new |
| 19 | recursive level. The default is 1. This |
| 20 | must be a non-negative integer, and may be |
| 21 | set by the caller before calling pprint(). |
| 22 | |
| 23 | MAX_WIDTH -- Maximum width of the display. This is only |
| 24 | used if the representation *can* be kept |
| 25 | less than MAX_WIDTH characters wide. May |
| 26 | be set by the user before calling pprint(). |
| 27 | |
| 28 | TAB_WIDTH -- The width represented by a single tab. This |
| 29 | value is typically 8, but 4 is the default |
| 30 | under MacOS. Can be changed by the user if |
| 31 | desired, but is probably not a good idea. |
| 32 | |
| 33 | pprint(seq [, stream]) -- The pretty-printer. This takes a Python |
| 34 | object (presumably a sequence, but that |
| 35 | doesn't matter) and an optional output |
| 36 | stream. See the function documentation |
| 37 | for details. |
| 38 | """ |
| 39 | |
| 40 | |
| 41 | INDENT_PER_LEVEL = 1 |
| 42 | |
| 43 | MAX_WIDTH = 80 |
| 44 | |
| 45 | import os |
| 46 | TAB_WIDTH = (os.name == 'mac' and 4) or 8 |
| 47 | del os |
| 48 | |
| 49 | |
| 50 | |
| 51 | def _indentation(cols): |
| 52 | "Create tabbed indentation string COLS columns wide." |
| 53 | |
| 54 | # This is used to reduce the byte-count for the output, allowing |
| 55 | # files created using this module to use as little external storage |
| 56 | # as possible. This is primarily intended to minimize impact on |
| 57 | # a user's quota when storing resource files, or for creating output |
| 58 | # intended for transmission. |
| 59 | |
| 60 | return ((cols / TAB_WIDTH) * '\t') + ((cols % TAB_WIDTH) * ' ') |
| 61 | |
| 62 | |
| 63 | |
| 64 | def pprint(seq, stream = None, indent = 0, allowance = 0): |
| 65 | """Pretty-print a list, tuple, or dictionary. |
| 66 | |
| 67 | pprint(seq [, stream]) ==> None |
| 68 | |
| 69 | If STREAM is provided, output is written to that stream, otherwise |
| 70 | sys.stdout is used. Indentation is done according to |
| 71 | INDENT_PER_LEVEL, which may be set to any non-negative integer |
| 72 | before calling this function. The output written on the stream is |
| 73 | a perfectly valid representation of the Python object passed in, |
| 74 | with indentation to suite human-readable interpretation. The |
| 75 | output can be used as input without error, given readable |
| 76 | representations of all sequence elements are available via repr(). |
| 77 | Output is restricted to MAX_WIDTH columns where possible. The |
| 78 | STREAM parameter must support the write() method with a single |
| 79 | parameter, which will always be a string. The output stream may be |
| 80 | a StringIO.StringIO object if the result is needed as a string. |
| 81 | """ |
| 82 | |
| 83 | if stream is None: |
| 84 | import sys |
| 85 | stream = sys.stdout |
| 86 | |
| 87 | from types import DictType, ListType, TupleType |
| 88 | |
| 89 | rep = `seq` |
| 90 | typ = type(seq) |
| 91 | sepLines = len(rep) > (MAX_WIDTH - 1 - indent - allowance) |
| 92 | |
| 93 | if sepLines and (typ is ListType or typ is TupleType): |
| 94 | # Pretty-print the sequence. |
| 95 | stream.write(((typ is ListType) and '[') or '(') |
| 96 | |
| 97 | length = len(seq) |
| 98 | if length: |
| 99 | indent = indent + INDENT_PER_LEVEL |
| 100 | pprint(seq[0], stream, indent, allowance + 1) |
| 101 | |
| 102 | if len(seq) > 1: |
| 103 | for ent in seq[1:]: |
| 104 | stream.write(',\n' + _indentation(indent)) |
| 105 | pprint(ent, stream, indent, allowance + 1) |
| 106 | |
| 107 | indent = indent - INDENT_PER_LEVEL |
| 108 | |
| 109 | stream.write(((typ is ListType) and ']') or ')') |
| 110 | |
| 111 | elif typ is DictType and sepLines: |
| 112 | stream.write('{') |
| 113 | |
| 114 | length = len(seq) |
| 115 | if length: |
| 116 | indent = indent + INDENT_PER_LEVEL |
| 117 | items = seq.items() |
| 118 | items.sort() |
| 119 | key, ent = items[0] |
| 120 | rep = `key` + ': ' |
| 121 | stream.write(rep) |
| 122 | pprint(ent, stream, indent + len(rep), allowance + 1) |
| 123 | |
| 124 | if len(items) > 1: |
| 125 | for key, ent in items[1:]: |
| 126 | rep = `key` + ': ' |
| 127 | stream.write(',\n' + _indentation(indent) + rep) |
| 128 | pprint(ent, stream, indent + len(rep), allowance + 1) |
| 129 | |
| 130 | indent = indent - INDENT_PER_LEVEL |
| 131 | |
| 132 | stream.write('}') |
| 133 | |
| 134 | else: |
| 135 | stream.write(rep) |
| 136 | |
| 137 | # Terminate the 'print' if we're not a recursive invocation. |
| 138 | if not indent: |
| 139 | stream.write('\n') |
| 140 | |
| 141 | |
| 142 | # |
| 143 | # end of pprint.py |