PyXR

c:\python24\lib \ pprint.py



0001 #  Author:      Fred L. Drake, Jr.
0002 #               fdrake@acm.org
0003 #
0004 #  This is a simple little module I wrote to make life easier.  I didn't
0005 #  see anything quite like it in the library, though I may have overlooked
0006 #  something.  I wrote this when I was trying to read some heavily nested
0007 #  tuples with fairly non-descriptive content.  This is modeled very much
0008 #  after Lisp/Scheme - style pretty-printing of lists.  If you find it
0009 #  useful, thank small children who sleep at night.
0010 
0011 """Support to pretty-print lists, tuples, & dictionaries recursively.
0012 
0013 Very simple, but useful, especially in debugging data structures.
0014 
0015 Classes
0016 -------
0017 
0018 PrettyPrinter()
0019     Handle pretty-printing operations onto a stream using a configured
0020     set of formatting parameters.
0021 
0022 Functions
0023 ---------
0024 
0025 pformat()
0026     Format a Python object into a pretty-printed representation.
0027 
0028 pprint()
0029     Pretty-print a Python object to a stream [default is sys.stdout].
0030 
0031 saferepr()
0032     Generate a 'standard' repr()-like value, but protect against recursive
0033     data structures.
0034 
0035 """
0036 
0037 import sys as _sys
0038 
0039 from cStringIO import StringIO as _StringIO
0040 
0041 __all__ = ["pprint","pformat","isreadable","isrecursive","saferepr",
0042            "PrettyPrinter"]
0043 
0044 # cache these for faster access:
0045 _commajoin = ", ".join
0046 _id = id
0047 _len = len
0048 _type = type
0049 
0050 
0051 def pprint(object, stream=None, indent=1, width=80, depth=None):
0052     """Pretty-print a Python object to a stream [default is sys.stdout]."""
0053     printer = PrettyPrinter(
0054         stream=stream, indent=indent, width=width, depth=depth)
0055     printer.pprint(object)
0056 
0057 def pformat(object, indent=1, width=80, depth=None):
0058     """Format a Python object into a pretty-printed representation."""
0059     return PrettyPrinter(indent=indent, width=width, depth=depth).pformat(object)
0060 
0061 def saferepr(object):
0062     """Version of repr() which can handle recursive data structures."""
0063     return _safe_repr(object, {}, None, 0)[0]
0064 
0065 def isreadable(object):
0066     """Determine if saferepr(object) is readable by eval()."""
0067     return _safe_repr(object, {}, None, 0)[1]
0068 
0069 def isrecursive(object):
0070     """Determine if object requires a recursive representation."""
0071     return _safe_repr(object, {}, None, 0)[2]
0072 
0073 class PrettyPrinter:
0074     def __init__(self, indent=1, width=80, depth=None, stream=None):
0075         """Handle pretty printing operations onto a stream using a set of
0076         configured parameters.
0077 
0078         indent
0079             Number of spaces to indent for each level of nesting.
0080 
0081         width
0082             Attempted maximum number of columns in the output.
0083 
0084         depth
0085             The maximum depth to print out nested structures.
0086 
0087         stream
0088             The desired output stream.  If omitted (or false), the standard
0089             output stream available at construction will be used.
0090 
0091         """
0092         indent = int(indent)
0093         width = int(width)
0094         assert indent >= 0, "indent must be >= 0"
0095         assert depth is None or depth > 0, "depth must be > 0"
0096         assert width, "width must be != 0"
0097         self._depth = depth
0098         self._indent_per_level = indent
0099         self._width = width
0100         if stream is not None:
0101             self._stream = stream
0102         else:
0103             self._stream = _sys.stdout
0104 
0105     def pprint(self, object):
0106         self._stream.write(self.pformat(object) + "\n")
0107 
0108     def pformat(self, object):
0109         sio = _StringIO()
0110         self._format(object, sio, 0, 0, {}, 0)
0111         return sio.getvalue()
0112 
0113     def isrecursive(self, object):
0114         return self.format(object, {}, 0, 0)[2]
0115 
0116     def isreadable(self, object):
0117         s, readable, recursive = self.format(object, {}, 0, 0)
0118         return readable and not recursive
0119 
0120     def _format(self, object, stream, indent, allowance, context, level):
0121         level = level + 1
0122         objid = _id(object)
0123         if objid in context:
0124             stream.write(_recursion(object))
0125             self._recursive = True
0126             self._readable = False
0127             return
0128         rep = self._repr(object, context, level - 1)
0129         typ = _type(object)
0130         sepLines = _len(rep) > (self._width - 1 - indent - allowance)
0131         write = stream.write
0132 
0133         if sepLines:
0134             r = typ.__repr__
0135             if issubclass(typ, dict) and r is dict.__repr__:
0136                 write('{')
0137                 if self._indent_per_level > 1:
0138                     write((self._indent_per_level - 1) * ' ')
0139                 length = _len(object)
0140                 if length:
0141                     context[objid] = 1
0142                     indent = indent + self._indent_per_level
0143                     items  = object.items()
0144                     items.sort()
0145                     key, ent = items[0]
0146                     rep = self._repr(key, context, level)
0147                     write(rep)
0148                     write(': ')
0149                     self._format(ent, stream, indent + _len(rep) + 2,
0150                                   allowance + 1, context, level)
0151                     if length > 1:
0152                         for key, ent in items[1:]:
0153                             rep = self._repr(key, context, level)
0154                             write(',\n%s%s: ' % (' '*indent, rep))
0155                             self._format(ent, stream, indent + _len(rep) + 2,
0156                                           allowance + 1, context, level)
0157                     indent = indent - self._indent_per_level
0158                     del context[objid]
0159                 write('}')
0160                 return
0161 
0162             if (issubclass(typ, list) and r is list.__repr__) or \
0163                (issubclass(typ, tuple) and r is tuple.__repr__):
0164                 if issubclass(typ, list):
0165                     write('[')
0166                     endchar = ']'
0167                 else:
0168                     write('(')
0169                     endchar = ')'
0170                 if self._indent_per_level > 1:
0171                     write((self._indent_per_level - 1) * ' ')
0172                 length = _len(object)
0173                 if length:
0174                     context[objid] = 1
0175                     indent = indent + self._indent_per_level
0176                     self._format(object[0], stream, indent, allowance + 1,
0177                                  context, level)
0178                     if length > 1:
0179                         for ent in object[1:]:
0180                             write(',\n' + ' '*indent)
0181                             self._format(ent, stream, indent,
0182                                           allowance + 1, context, level)
0183                     indent = indent - self._indent_per_level
0184                     del context[objid]
0185                 if issubclass(typ, tuple) and length == 1:
0186                     write(',')
0187                 write(endchar)
0188                 return
0189 
0190         write(rep)
0191 
0192     def _repr(self, object, context, level):
0193         repr, readable, recursive = self.format(object, context.copy(),
0194                                                 self._depth, level)
0195         if not readable:
0196             self._readable = False
0197         if recursive:
0198             self._recursive = True
0199         return repr
0200 
0201     def format(self, object, context, maxlevels, level):
0202         """Format object for a specific context, returning a string
0203         and flags indicating whether the representation is 'readable'
0204         and whether the object represents a recursive construct.
0205         """
0206         return _safe_repr(object, context, maxlevels, level)
0207 
0208 
0209 # Return triple (repr_string, isreadable, isrecursive).
0210 
0211 def _safe_repr(object, context, maxlevels, level):
0212     typ = _type(object)
0213     if typ is str:
0214         if 'locale' not in _sys.modules:
0215             return repr(object), True, False
0216         if "'" in object and '"' not in object:
0217             closure = '"'
0218             quotes = {'"': '\\"'}
0219         else:
0220             closure = "'"
0221             quotes = {"'": "\\'"}
0222         qget = quotes.get
0223         sio = _StringIO()
0224         write = sio.write
0225         for char in object:
0226             if char.isalpha():
0227                 write(char)
0228             else:
0229                 write(qget(char, repr(char)[1:-1]))
0230         return ("%s%s%s" % (closure, sio.getvalue(), closure)), True, False
0231 
0232     r = typ.__repr__
0233     if issubclass(typ, dict) and r is dict.__repr__:
0234         if not object:
0235             return "{}", True, False
0236         objid = _id(object)
0237         if maxlevels and level > maxlevels:
0238             return "{...}", False, objid in context
0239         if objid in context:
0240             return _recursion(object), False, True
0241         context[objid] = 1
0242         readable = True
0243         recursive = False
0244         components = []
0245         append = components.append
0246         level += 1
0247         saferepr = _safe_repr
0248         for k, v in object.iteritems():
0249             krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
0250             vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
0251             append("%s: %s" % (krepr, vrepr))
0252             readable = readable and kreadable and vreadable
0253             if krecur or vrecur:
0254                 recursive = True
0255         del context[objid]
0256         return "{%s}" % _commajoin(components), readable, recursive
0257 
0258     if (issubclass(typ, list) and r is list.__repr__) or \
0259        (issubclass(typ, tuple) and r is tuple.__repr__):
0260         if issubclass(typ, list):
0261             if not object:
0262                 return "[]", True, False
0263             format = "[%s]"
0264         elif _len(object) == 1:
0265             format = "(%s,)"
0266         else:
0267             if not object:
0268                 return "()", True, False
0269             format = "(%s)"
0270         objid = _id(object)
0271         if maxlevels and level > maxlevels:
0272             return format % "...", False, objid in context
0273         if objid in context:
0274             return _recursion(object), False, True
0275         context[objid] = 1
0276         readable = True
0277         recursive = False
0278         components = []
0279         append = components.append
0280         level += 1
0281         for o in object:
0282             orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)
0283             append(orepr)
0284             if not oreadable:
0285                 readable = False
0286             if orecur:
0287                 recursive = True
0288         del context[objid]
0289         return format % _commajoin(components), readable, recursive
0290 
0291     rep = repr(object)
0292     return rep, (rep and not rep.startswith('<')), False
0293 
0294 
0295 def _recursion(object):
0296     return ("<Recursion on %s with id=%s>"
0297             % (_type(object).__name__, _id(object)))
0298 
0299 
0300 def _perfcheck(object=None):
0301     import time
0302     if object is None:
0303         object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
0304     p = PrettyPrinter()
0305     t1 = time.time()
0306     _safe_repr(object, {}, None, 0)
0307     t2 = time.time()
0308     p.pformat(object)
0309     t3 = time.time()
0310     print "_safe_repr:", t2 - t1
0311     print "pformat:", t3 - t2
0312 
0313 if __name__ == "__main__":
0314     _perfcheck()
0315 

Generated by PyXR 0.9.4
SourceForge.net Logo