# pprint.py # # Author: Fred L. Drake, Jr. # fdrake@vt.edu # # 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 at least somewhat useful, especially in debugging data structures. 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. pprint(seq [, stream]) -- The pretty-printer. This takes a Python object (presumably a sequence, but that doesn't matter) and an optional output stream. See the function documentation for details. """ INDENT_PER_LEVEL = 1 MAX_WIDTH = 80 import os TAB_WIDTH = (os.name == 'mac' and 4) or 8 del os def _indentation(cols): "Create tabbed indentation string COLS columns wide." # This is used to reduce the byte-count for the output, allowing # files created using this module to use as little external storage # as possible. This is primarily intended to minimize impact on # a user's quota when storing resource files, or for creating output # intended for transmission. return ((cols / TAB_WIDTH) * '\t') + ((cols % TAB_WIDTH) * ' ') def pprint(seq, stream = None, indent = 0, allowance = 0): """Pretty-print a list, tuple, or dictionary. pprint(seq [, stream]) ==> None If STREAM is provided, output is written to that stream, otherwise sys.stdout is used. 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 suite human-readable interpretation. The output can be used as input without error, given readable representations of all sequence elements are available via repr(). Output is restricted to MAX_WIDTH columns where possible. The STREAM parameter must support the write() method with a single parameter, which will always be a string. The output stream may be a StringIO.StringIO object if the result is needed as a string. """ if stream is None: import sys stream = sys.stdout from types import DictType, ListType, TupleType 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 pprint.py