mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 03:44:55 +00:00 
			
		
		
		
	svn+ssh://pythondev@svn.python.org/python/trunk ........ r63119 | benjamin.peterson | 2008-05-11 20:41:23 -0400 (Sun, 11 May 2008) | 2 lines #2196 hasattr now allows SystemExit and KeyboardInterrupt to propagate ........ r63122 | benjamin.peterson | 2008-05-11 20:46:49 -0400 (Sun, 11 May 2008) | 2 lines make message slightly more informative, so there's no chance of misunderstanding it ........ r63158 | ronald.oussoren | 2008-05-12 07:24:33 -0400 (Mon, 12 May 2008) | 5 lines Remove references to platform 'mac' The 'mac' platform (that is, os.name == 'mac') was used for the MacOS 9 port, which is no longer supported (as of Python 2.4 IIRC). ........ r63159 | ronald.oussoren | 2008-05-12 07:31:05 -0400 (Mon, 12 May 2008) | 8 lines MacOSX: remove dependency on Carbon package for urllib This patch removes the dependency on the Carbon package from urllib. The mac-specific code for getting proxy configuration is now writting in Python using ctypes and uses the SystemConfiguration framework instead of InternetConfig. Also provides a mac-specific implementation of proxy_bypass. ........ r63162 | eric.smith | 2008-05-12 10:00:01 -0400 (Mon, 12 May 2008) | 1 line Added 'n' presentation type for integers. ........ r63164 | georg.brandl | 2008-05-12 12:26:52 -0400 (Mon, 12 May 2008) | 2 lines #1713041: fix pprint's handling of maximum depth. ........ r63170 | georg.brandl | 2008-05-12 12:53:42 -0400 (Mon, 12 May 2008) | 2 lines Fix parameter name for enumerate(). ........ r63173 | georg.brandl | 2008-05-12 13:01:58 -0400 (Mon, 12 May 2008) | 2 lines #2766: remove code without effect. ........ r63174 | georg.brandl | 2008-05-12 13:04:10 -0400 (Mon, 12 May 2008) | 3 lines #2767: don't clear globs in run() call, since they could be needed in tearDown, which clears them at the end. ........ r63175 | georg.brandl | 2008-05-12 13:14:51 -0400 (Mon, 12 May 2008) | 2 lines #1760: try-except-finally is one statement since PEP 341. ........ r63186 | amaury.forgeotdarc | 2008-05-12 17:30:24 -0400 (Mon, 12 May 2008) | 2 lines Sync code with documentation, and remove Win95 support in winsound module. ........ r63189 | amaury.forgeotdarc | 2008-05-12 18:21:39 -0400 (Mon, 12 May 2008) | 3 lines Adapt test_pyclbr to the new version of urllib.py: The new mac-specific functions must be ignored. ........
		
			
				
	
	
		
			344 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			344 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#  Author:      Fred L. Drake, Jr.
 | 
						|
#               fdrake@acm.org
 | 
						|
#
 | 
						|
#  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 modeled 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.
 | 
						|
 | 
						|
Classes
 | 
						|
-------
 | 
						|
 | 
						|
PrettyPrinter()
 | 
						|
    Handle pretty-printing operations onto a stream using a configured
 | 
						|
    set of formatting parameters.
 | 
						|
 | 
						|
Functions
 | 
						|
---------
 | 
						|
 | 
						|
pformat()
 | 
						|
    Format a Python object into a pretty-printed representation.
 | 
						|
 | 
						|
pprint()
 | 
						|
    Pretty-print a Python object to a stream [default is sys.stdout].
 | 
						|
 | 
						|
saferepr()
 | 
						|
    Generate a 'standard' repr()-like value, but protect against recursive
 | 
						|
    data structures.
 | 
						|
 | 
						|
"""
 | 
						|
 | 
						|
import sys as _sys
 | 
						|
 | 
						|
from io import StringIO as _StringIO
 | 
						|
 | 
						|
__all__ = ["pprint","pformat","isreadable","isrecursive","saferepr",
 | 
						|
           "PrettyPrinter"]
 | 
						|
 | 
						|
# cache these for faster access:
 | 
						|
_commajoin = ", ".join
 | 
						|
_id = id
 | 
						|
_len = len
 | 
						|
_type = type
 | 
						|
 | 
						|
 | 
						|
def pprint(object, stream=None, indent=1, width=80, depth=None):
 | 
						|
    """Pretty-print a Python object to a stream [default is sys.stdout]."""
 | 
						|
    printer = PrettyPrinter(
 | 
						|
        stream=stream, indent=indent, width=width, depth=depth)
 | 
						|
    printer.pprint(object)
 | 
						|
 | 
						|
def pformat(object, indent=1, width=80, depth=None):
 | 
						|
    """Format a Python object into a pretty-printed representation."""
 | 
						|
    return PrettyPrinter(indent=indent, width=width, depth=depth).pformat(object)
 | 
						|
 | 
						|
def saferepr(object):
 | 
						|
    """Version of repr() which can handle recursive data structures."""
 | 
						|
    return _safe_repr(object, {}, None, 0)[0]
 | 
						|
 | 
						|
def isreadable(object):
 | 
						|
    """Determine if saferepr(object) is readable by eval()."""
 | 
						|
    return _safe_repr(object, {}, None, 0)[1]
 | 
						|
 | 
						|
def isrecursive(object):
 | 
						|
    """Determine if object requires a recursive representation."""
 | 
						|
    return _safe_repr(object, {}, None, 0)[2]
 | 
						|
 | 
						|
class PrettyPrinter:
 | 
						|
    def __init__(self, indent=1, width=80, depth=None, stream=None):
 | 
						|
        """Handle pretty printing operations onto a stream using a set of
 | 
						|
        configured parameters.
 | 
						|
 | 
						|
        indent
 | 
						|
            Number of spaces to indent for each level of nesting.
 | 
						|
 | 
						|
        width
 | 
						|
            Attempted maximum number of columns in the output.
 | 
						|
 | 
						|
        depth
 | 
						|
            The maximum depth to print out nested structures.
 | 
						|
 | 
						|
        stream
 | 
						|
            The desired output stream.  If omitted (or false), the standard
 | 
						|
            output stream available at construction will be used.
 | 
						|
 | 
						|
        """
 | 
						|
        indent = int(indent)
 | 
						|
        width = int(width)
 | 
						|
        assert indent >= 0, "indent must be >= 0"
 | 
						|
        assert depth is None or depth > 0, "depth must be > 0"
 | 
						|
        assert width, "width must be != 0"
 | 
						|
        self._depth = depth
 | 
						|
        self._indent_per_level = indent
 | 
						|
        self._width = width
 | 
						|
        if stream is not None:
 | 
						|
            self._stream = stream
 | 
						|
        else:
 | 
						|
            self._stream = _sys.stdout
 | 
						|
 | 
						|
    def pprint(self, object):
 | 
						|
        self._format(object, self._stream, 0, 0, {}, 0)
 | 
						|
        self._stream.write("\n")
 | 
						|
 | 
						|
    def pformat(self, object):
 | 
						|
        sio = _StringIO()
 | 
						|
        self._format(object, sio, 0, 0, {}, 0)
 | 
						|
        return sio.getvalue()
 | 
						|
 | 
						|
    def isrecursive(self, object):
 | 
						|
        return self.format(object, {}, 0, 0)[2]
 | 
						|
 | 
						|
    def isreadable(self, object):
 | 
						|
        s, readable, recursive = self.format(object, {}, 0, 0)
 | 
						|
        return readable and not recursive
 | 
						|
 | 
						|
    def _format(self, object, stream, indent, allowance, context, level):
 | 
						|
        level = level + 1
 | 
						|
        objid = _id(object)
 | 
						|
        if objid in context:
 | 
						|
            stream.write(_recursion(object))
 | 
						|
            self._recursive = True
 | 
						|
            self._readable = False
 | 
						|
            return
 | 
						|
        rep = self._repr(object, context, level - 1)
 | 
						|
        typ = _type(object)
 | 
						|
        sepLines = _len(rep) > (self._width - 1 - indent - allowance)
 | 
						|
        write = stream.write
 | 
						|
 | 
						|
        if self._depth and level > self._depth:
 | 
						|
            write(rep)
 | 
						|
            return
 | 
						|
 | 
						|
        if sepLines:
 | 
						|
            r = getattr(typ, "__repr__", None)
 | 
						|
            if issubclass(typ, dict) and r is dict.__repr__:
 | 
						|
                write('{')
 | 
						|
                if self._indent_per_level > 1:
 | 
						|
                    write((self._indent_per_level - 1) * ' ')
 | 
						|
                length = _len(object)
 | 
						|
                if length:
 | 
						|
                    context[objid] = 1
 | 
						|
                    indent = indent + self._indent_per_level
 | 
						|
                    items  = sorted(object.items())
 | 
						|
                    key, ent = items[0]
 | 
						|
                    rep = self._repr(key, context, level)
 | 
						|
                    write(rep)
 | 
						|
                    write(': ')
 | 
						|
                    self._format(ent, stream, indent + _len(rep) + 2,
 | 
						|
                                  allowance + 1, context, level)
 | 
						|
                    if length > 1:
 | 
						|
                        for key, ent in items[1:]:
 | 
						|
                            rep = self._repr(key, context, level)
 | 
						|
                            write(',\n%s%s: ' % (' '*indent, rep))
 | 
						|
                            self._format(ent, stream, indent + _len(rep) + 2,
 | 
						|
                                          allowance + 1, context, level)
 | 
						|
                    indent = indent - self._indent_per_level
 | 
						|
                    del context[objid]
 | 
						|
                write('}')
 | 
						|
                return
 | 
						|
 | 
						|
            if ((issubclass(typ, list) and r is list.__repr__) or
 | 
						|
                (issubclass(typ, tuple) and r is tuple.__repr__) or
 | 
						|
                (issubclass(typ, set) and r is set.__repr__) or
 | 
						|
                (issubclass(typ, frozenset) and r is frozenset.__repr__)
 | 
						|
               ):
 | 
						|
                length = _len(object)
 | 
						|
                if issubclass(typ, list):
 | 
						|
                    write('[')
 | 
						|
                    endchar = ']'
 | 
						|
                elif issubclass(typ, set):
 | 
						|
                    if not length:
 | 
						|
                        write('set()')
 | 
						|
                        return
 | 
						|
                    write('{')
 | 
						|
                    endchar = '}'
 | 
						|
                    object = sorted(object)
 | 
						|
                elif issubclass(typ, frozenset):
 | 
						|
                    if not length:
 | 
						|
                        write('frozenset()')
 | 
						|
                        return
 | 
						|
                    write('frozenset({')
 | 
						|
                    endchar = '})'
 | 
						|
                    object = sorted(object)
 | 
						|
                    indent += 10
 | 
						|
                else:
 | 
						|
                    write('(')
 | 
						|
                    endchar = ')'
 | 
						|
                if self._indent_per_level > 1:
 | 
						|
                    write((self._indent_per_level - 1) * ' ')
 | 
						|
                if length:
 | 
						|
                    context[objid] = 1
 | 
						|
                    indent = indent + self._indent_per_level
 | 
						|
                    self._format(object[0], stream, indent, allowance + 1,
 | 
						|
                                 context, level)
 | 
						|
                    if length > 1:
 | 
						|
                        for ent in object[1:]:
 | 
						|
                            write(',\n' + ' '*indent)
 | 
						|
                            self._format(ent, stream, indent,
 | 
						|
                                          allowance + 1, context, level)
 | 
						|
                    indent = indent - self._indent_per_level
 | 
						|
                    del context[objid]
 | 
						|
                if issubclass(typ, tuple) and length == 1:
 | 
						|
                    write(',')
 | 
						|
                write(endchar)
 | 
						|
                return
 | 
						|
 | 
						|
        write(rep)
 | 
						|
 | 
						|
    def _repr(self, object, context, level):
 | 
						|
        repr, readable, recursive = self.format(object, context.copy(),
 | 
						|
                                                self._depth, level)
 | 
						|
        if not readable:
 | 
						|
            self._readable = False
 | 
						|
        if recursive:
 | 
						|
            self._recursive = True
 | 
						|
        return repr
 | 
						|
 | 
						|
    def format(self, object, context, maxlevels, level):
 | 
						|
        """Format object for a specific context, returning a string
 | 
						|
        and flags indicating whether the representation is 'readable'
 | 
						|
        and whether the object represents a recursive construct.
 | 
						|
        """
 | 
						|
        return _safe_repr(object, context, maxlevels, level)
 | 
						|
 | 
						|
 | 
						|
# Return triple (repr_string, isreadable, isrecursive).
 | 
						|
 | 
						|
def _safe_repr(object, context, maxlevels, level):
 | 
						|
    typ = _type(object)
 | 
						|
    if typ is str:
 | 
						|
        if 'locale' not in _sys.modules:
 | 
						|
            return repr(object), True, False
 | 
						|
        if "'" in object and '"' not in object:
 | 
						|
            closure = '"'
 | 
						|
            quotes = {'"': '\\"'}
 | 
						|
        else:
 | 
						|
            closure = "'"
 | 
						|
            quotes = {"'": "\\'"}
 | 
						|
        qget = quotes.get
 | 
						|
        sio = _StringIO()
 | 
						|
        write = sio.write
 | 
						|
        for char in object:
 | 
						|
            if char.isalpha():
 | 
						|
                write(char)
 | 
						|
            else:
 | 
						|
                write(qget(char, repr(char)[1:-1]))
 | 
						|
        return ("%s%s%s" % (closure, sio.getvalue(), closure)), True, False
 | 
						|
 | 
						|
    r = getattr(typ, "__repr__", None)
 | 
						|
    if issubclass(typ, dict) and r is dict.__repr__:
 | 
						|
        if not object:
 | 
						|
            return "{}", True, False
 | 
						|
        objid = _id(object)
 | 
						|
        if maxlevels and level >= maxlevels:
 | 
						|
            return "{...}", False, objid in context
 | 
						|
        if objid in context:
 | 
						|
            return _recursion(object), False, True
 | 
						|
        context[objid] = 1
 | 
						|
        readable = True
 | 
						|
        recursive = False
 | 
						|
        components = []
 | 
						|
        append = components.append
 | 
						|
        level += 1
 | 
						|
        saferepr = _safe_repr
 | 
						|
        items = object.items()
 | 
						|
        try:
 | 
						|
            items = sorted(items)
 | 
						|
        except TypeError:
 | 
						|
            def sortkey(item):
 | 
						|
                key, value = item
 | 
						|
                return str(type(key)), key, value
 | 
						|
            items = sorted(items, key=sortkey)
 | 
						|
        for k, v in items:
 | 
						|
            krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
 | 
						|
            vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
 | 
						|
            append("%s: %s" % (krepr, vrepr))
 | 
						|
            readable = readable and kreadable and vreadable
 | 
						|
            if krecur or vrecur:
 | 
						|
                recursive = True
 | 
						|
        del context[objid]
 | 
						|
        return "{%s}" % _commajoin(components), readable, recursive
 | 
						|
 | 
						|
    if (issubclass(typ, list) and r is list.__repr__) or \
 | 
						|
       (issubclass(typ, tuple) and r is tuple.__repr__):
 | 
						|
        if issubclass(typ, list):
 | 
						|
            if not object:
 | 
						|
                return "[]", True, False
 | 
						|
            format = "[%s]"
 | 
						|
        elif _len(object) == 1:
 | 
						|
            format = "(%s,)"
 | 
						|
        else:
 | 
						|
            if not object:
 | 
						|
                return "()", True, False
 | 
						|
            format = "(%s)"
 | 
						|
        objid = _id(object)
 | 
						|
        if maxlevels and level >= maxlevels:
 | 
						|
            return format % "...", False, objid in context
 | 
						|
        if objid in context:
 | 
						|
            return _recursion(object), False, True
 | 
						|
        context[objid] = 1
 | 
						|
        readable = True
 | 
						|
        recursive = False
 | 
						|
        components = []
 | 
						|
        append = components.append
 | 
						|
        level += 1
 | 
						|
        for o in object:
 | 
						|
            orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)
 | 
						|
            append(orepr)
 | 
						|
            if not oreadable:
 | 
						|
                readable = False
 | 
						|
            if orecur:
 | 
						|
                recursive = True
 | 
						|
        del context[objid]
 | 
						|
        return format % _commajoin(components), readable, recursive
 | 
						|
 | 
						|
    rep = repr(object)
 | 
						|
    return rep, (rep and not rep.startswith('<')), False
 | 
						|
 | 
						|
 | 
						|
def _recursion(object):
 | 
						|
    return ("<Recursion on %s with id=%s>"
 | 
						|
            % (_type(object).__name__, _id(object)))
 | 
						|
 | 
						|
 | 
						|
def _perfcheck(object=None):
 | 
						|
    import time
 | 
						|
    if object is None:
 | 
						|
        object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
 | 
						|
    p = PrettyPrinter()
 | 
						|
    t1 = time.time()
 | 
						|
    _safe_repr(object, {}, None, 0)
 | 
						|
    t2 = time.time()
 | 
						|
    p.pformat(object)
 | 
						|
    t3 = time.time()
 | 
						|
    print("_safe_repr:", t2 - t1)
 | 
						|
    print("pformat:", t3 - t2)
 | 
						|
 | 
						|
if __name__ == "__main__":
 | 
						|
    _perfcheck()
 |