| # pprint.py |
| # |
| # Author: Fred L. Drake, Jr. |
| # fdrake@cnri.reston.va.us, fdrake@intr.net |
| # |
| # This is a simple little module I wrote to make life easier. I didn't |
| # see anything quite like it in the library, though I may have overlooked |
| # something. I wrote this when I was trying to read some heavily nested |
| # tuples with fairly non-descriptive content. This is modelled very much |
| # after Lisp/Scheme - style pretty-printing of lists. If you find it |
| # useful, thank small children who sleep at night. |
| |
| """Support to pretty-print lists, tuples, & dictionaries recursively. |
| Very simple, but useful, especially in debugging data structures. |
| |
| Constants |
| --------- |
| |
| INDENT_PER_LEVEL |
| Amount of indentation to use for each new recursive level. The |
| default is 1. This must be a non-negative integer, and may be set |
| by the caller before calling pprint(). |
| |
| MAX_WIDTH |
| Maximum width of the display. This is only used if the |
| representation *can* be kept less than MAX_WIDTH characters wide. |
| May be set by the user before calling pprint(). |
| |
| TAB_WIDTH |
| The width represented by a single tab. This value is typically 8, |
| but 4 is the default under MacOS. Can be changed by the user if |
| desired, but is probably not a good idea. |
| """ |
| |
| INDENT_PER_LEVEL = 1 |
| |
| MAX_WIDTH = 80 |
| |
| import os |
| TAB_WIDTH = (os.name == 'mac' and 4) or 8 |
| del os |
| |
| from types import DictType, ListType, TupleType |
| |
| |
| def _indentation(cols): |
| """Create tabbed indentation string. |
| |
| cols |
| Width of the indentation, in columns. |
| """ |
| return ((cols / TAB_WIDTH) * '\t') + ((cols % TAB_WIDTH) * ' ') |
| |
| |
| def pprint(seq, stream = None, indent = 0, allowance = 0): |
| """Pretty-print a list, tuple, or dictionary. |
| |
| seq |
| List, tuple, or dictionary object to be pretty-printed. Other |
| object types are permitted by are not specially interpreted. |
| |
| stream |
| Output stream. If not provided, `sys.stdout' is used. This |
| parameter must support the `write()' method with a single |
| parameter, which will always be a string. It may be a |
| `StringIO.StringIO' object if the result is needed as a |
| string. |
| |
| Indentation is done according to `INDENT_PER_LEVEL', which may be |
| set to any non-negative integer before calling this function. The |
| output written on the stream is a perfectly valid representation |
| of the Python object passed in, with indentation to assist |
| human-readable interpretation. The output can be used as input |
| without error, given readable representations of all elements are |
| available via `repr()'. Output is restricted to `MAX_WIDTH' |
| columns where possible. |
| """ |
| if stream is None: |
| import sys |
| stream = sys.stdout |
| |
| rep = `seq` |
| typ = type(seq) |
| sepLines = len(rep) > (MAX_WIDTH - 1 - indent - allowance) |
| |
| if sepLines and (typ is ListType or typ is TupleType): |
| # Pretty-print the sequence. |
| stream.write(((typ is ListType) and '[') or '(') |
| |
| length = len(seq) |
| if length: |
| indent = indent + INDENT_PER_LEVEL |
| pprint(seq[0], stream, indent, allowance + 1) |
| |
| if len(seq) > 1: |
| for ent in seq[1:]: |
| stream.write(',\n' + _indentation(indent)) |
| pprint(ent, stream, indent, allowance + 1) |
| |
| indent = indent - INDENT_PER_LEVEL |
| |
| stream.write(((typ is ListType) and ']') or ')') |
| |
| elif typ is DictType and sepLines: |
| stream.write('{') |
| |
| length = len(seq) |
| if length: |
| indent = indent + INDENT_PER_LEVEL |
| items = seq.items() |
| items.sort() |
| key, ent = items[0] |
| rep = `key` + ': ' |
| stream.write(rep) |
| pprint(ent, stream, indent + len(rep), allowance + 1) |
| |
| if len(items) > 1: |
| for key, ent in items[1:]: |
| rep = `key` + ': ' |
| stream.write(',\n' + _indentation(indent) + rep) |
| pprint(ent, stream, indent + len(rep), allowance + 1) |
| |
| indent = indent - INDENT_PER_LEVEL |
| |
| stream.write('}') |
| |
| else: |
| stream.write(rep) |
| |
| # Terminate the 'print' if we're not a recursive invocation. |
| if not indent: |
| stream.write('\n') |
| |
| |
| # |
| # end of file |