1edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep#  Author:      Fred L. Drake, Jr.
2edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep#               fdrake@acm.org
3edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep#
4edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep#  This is a simple little module I wrote to make life easier.  I didn't
5edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep#  see anything quite like it in the library, though I may have overlooked
6edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep#  something.  I wrote this when I was trying to read some heavily nested
7edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep#  tuples with fairly non-descriptive content.  This is modeled very much
8edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep#  after Lisp/Scheme - style pretty-printing of lists.  If you find it
9edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep#  useful, thank small children who sleep at night.
10edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
11edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep"""Support to pretty-print lists, tuples, & dictionaries recursively.
12edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
13edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepVery simple, but useful, especially in debugging data structures.
14edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
15edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepClasses
16edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep-------
17edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
18edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepPrettyPrinter()
19edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    Handle pretty-printing operations onto a stream using a configured
20edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    set of formatting parameters.
21edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
22edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFunctions
23edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep---------
24edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
25edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoeppformat()
26edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    Format a Python object into a pretty-printed representation.
27edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
28edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoeppprint()
29edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    Pretty-print a Python object to a stream [default is sys.stdout].
30edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
31edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepsaferepr()
32edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    Generate a 'standard' repr()-like value, but protect against recursive
33edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    data structures.
34edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
35edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep"""
36edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
37edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport sys as _sys
38edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport warnings
39edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
40edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoeptry:
41edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    from cStringIO import StringIO as _StringIO
42edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepexcept ImportError:
43edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    from StringIO import StringIO as _StringIO
44edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
45edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep__all__ = ["pprint","pformat","isreadable","isrecursive","saferepr",
46edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           "PrettyPrinter"]
47edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
48edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# cache these for faster access:
49edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep_commajoin = ", ".join
50edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep_id = id
51edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep_len = len
52edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep_type = type
53edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
54edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
55edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef pprint(object, stream=None, indent=1, width=80, depth=None):
56edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    """Pretty-print a Python object to a stream [default is sys.stdout]."""
57edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    printer = PrettyPrinter(
58edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        stream=stream, indent=indent, width=width, depth=depth)
59edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    printer.pprint(object)
60edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
61edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef pformat(object, indent=1, width=80, depth=None):
62edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    """Format a Python object into a pretty-printed representation."""
63edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    return PrettyPrinter(indent=indent, width=width, depth=depth).pformat(object)
64edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
65edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef saferepr(object):
66edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    """Version of repr() which can handle recursive data structures."""
67edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    return _safe_repr(object, {}, None, 0)[0]
68edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
69edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef isreadable(object):
70edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    """Determine if saferepr(object) is readable by eval()."""
71edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    return _safe_repr(object, {}, None, 0)[1]
72edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
73edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef isrecursive(object):
74edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    """Determine if object requires a recursive representation."""
75edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    return _safe_repr(object, {}, None, 0)[2]
76edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
77edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef _sorted(iterable):
78edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    with warnings.catch_warnings():
79edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if _sys.py3kwarning:
80edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            warnings.filterwarnings("ignore", "comparing unequal types "
81edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                                    "not supported", DeprecationWarning)
82edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        return sorted(iterable)
83edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
84edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass PrettyPrinter:
85edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def __init__(self, indent=1, width=80, depth=None, stream=None):
86edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        """Handle pretty printing operations onto a stream using a set of
87edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        configured parameters.
88edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
89edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        indent
90edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            Number of spaces to indent for each level of nesting.
91edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
92edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        width
93edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            Attempted maximum number of columns in the output.
94edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
95edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        depth
96edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            The maximum depth to print out nested structures.
97edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
98edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        stream
99edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            The desired output stream.  If omitted (or false), the standard
100edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            output stream available at construction will be used.
101edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
102edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        """
103edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        indent = int(indent)
104edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        width = int(width)
105edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        assert indent >= 0, "indent must be >= 0"
106edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        assert depth is None or depth > 0, "depth must be > 0"
107edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        assert width, "width must be != 0"
108edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._depth = depth
109edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._indent_per_level = indent
110edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._width = width
111edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if stream is not None:
112edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self._stream = stream
113edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        else:
114edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self._stream = _sys.stdout
115edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
116edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def pprint(self, object):
117edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._format(object, self._stream, 0, 0, {}, 0)
118edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._stream.write("\n")
119edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
120edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def pformat(self, object):
121edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        sio = _StringIO()
122edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._format(object, sio, 0, 0, {}, 0)
123edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        return sio.getvalue()
124edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
125edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def isrecursive(self, object):
126edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        return self.format(object, {}, 0, 0)[2]
127edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
128edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def isreadable(self, object):
129edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s, readable, recursive = self.format(object, {}, 0, 0)
130edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        return readable and not recursive
131edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
132edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def _format(self, object, stream, indent, allowance, context, level):
133edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        level = level + 1
134edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        objid = _id(object)
135edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if objid in context:
136edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            stream.write(_recursion(object))
137edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self._recursive = True
138edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self._readable = False
139edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            return
140edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        rep = self._repr(object, context, level - 1)
141edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        typ = _type(object)
142edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        sepLines = _len(rep) > (self._width - 1 - indent - allowance)
143edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        write = stream.write
144edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
145edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if self._depth and level > self._depth:
146edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            write(rep)
147edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            return
148edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
149edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        r = getattr(typ, "__repr__", None)
150edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if issubclass(typ, dict) and r is dict.__repr__:
151edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            write('{')
152edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            if self._indent_per_level > 1:
153edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                write((self._indent_per_level - 1) * ' ')
154edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            length = _len(object)
155edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            if length:
156edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                context[objid] = 1
157edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                indent = indent + self._indent_per_level
158edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                items = _sorted(object.items())
159edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                key, ent = items[0]
160edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                rep = self._repr(key, context, level)
161edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                write(rep)
162edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                write(': ')
163edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                self._format(ent, stream, indent + _len(rep) + 2,
164edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                              allowance + 1, context, level)
165edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                if length > 1:
166edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                    for key, ent in items[1:]:
167edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                        rep = self._repr(key, context, level)
168edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                        if sepLines:
169edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                            write(',\n%s%s: ' % (' '*indent, rep))
170edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                        else:
171edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                            write(', %s: ' % rep)
172edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                        self._format(ent, stream, indent + _len(rep) + 2,
173edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                                      allowance + 1, context, level)
174edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                indent = indent - self._indent_per_level
175edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                del context[objid]
176edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            write('}')
177edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            return
178edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
179edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if ((issubclass(typ, list) and r is list.__repr__) or
180edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            (issubclass(typ, tuple) and r is tuple.__repr__) or
181edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            (issubclass(typ, set) and r is set.__repr__) or
182edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            (issubclass(typ, frozenset) and r is frozenset.__repr__)
183edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           ):
184edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            length = _len(object)
185edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            if issubclass(typ, list):
186edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                write('[')
187edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                endchar = ']'
188edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            elif issubclass(typ, set):
189edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                if not length:
190edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                    write('set()')
191edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                    return
192edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                write('set([')
193edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                endchar = '])'
194edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                object = _sorted(object)
195edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                indent += 4
196edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            elif issubclass(typ, frozenset):
197edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                if not length:
198edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                    write('frozenset()')
199edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                    return
200edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                write('frozenset([')
201edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                endchar = '])'
202edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                object = _sorted(object)
203edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                indent += 10
204edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            else:
205edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                write('(')
206edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                endchar = ')'
207edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            if self._indent_per_level > 1 and sepLines:
208edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                write((self._indent_per_level - 1) * ' ')
209edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            if length:
210edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                context[objid] = 1
211edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                indent = indent + self._indent_per_level
212edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                self._format(object[0], stream, indent, allowance + 1,
213edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                             context, level)
214edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                if length > 1:
215edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                    for ent in object[1:]:
216edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                        if sepLines:
217edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                            write(',\n' + ' '*indent)
218edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                        else:
219edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                            write(', ')
220edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                        self._format(ent, stream, indent,
221edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                                      allowance + 1, context, level)
222edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                indent = indent - self._indent_per_level
223edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                del context[objid]
224edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            if issubclass(typ, tuple) and length == 1:
225edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                write(',')
226edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            write(endchar)
227edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            return
228edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
229edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        write(rep)
230edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
231edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def _repr(self, object, context, level):
232edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        repr, readable, recursive = self.format(object, context.copy(),
233edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                                                self._depth, level)
234edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if not readable:
235edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self._readable = False
236edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if recursive:
237edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self._recursive = True
238edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        return repr
239edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
240edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def format(self, object, context, maxlevels, level):
241edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        """Format object for a specific context, returning a string
242edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        and flags indicating whether the representation is 'readable'
243edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        and whether the object represents a recursive construct.
244edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        """
245edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        return _safe_repr(object, context, maxlevels, level)
246edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
247edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
248edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Return triple (repr_string, isreadable, isrecursive).
249edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
250edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef _safe_repr(object, context, maxlevels, level):
251edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    typ = _type(object)
252edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    if typ is str:
253edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if 'locale' not in _sys.modules:
254edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            return repr(object), True, False
255edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if "'" in object and '"' not in object:
256edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            closure = '"'
257edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            quotes = {'"': '\\"'}
258edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        else:
259edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            closure = "'"
260edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            quotes = {"'": "\\'"}
261edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        qget = quotes.get
262edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        sio = _StringIO()
263edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        write = sio.write
264edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for char in object:
265edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            if char.isalpha():
266edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                write(char)
267edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            else:
268edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                write(qget(char, repr(char)[1:-1]))
269edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        return ("%s%s%s" % (closure, sio.getvalue(), closure)), True, False
270edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
271edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    r = getattr(typ, "__repr__", None)
272edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    if issubclass(typ, dict) and r is dict.__repr__:
273edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if not object:
274edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            return "{}", True, False
275edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        objid = _id(object)
276edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if maxlevels and level >= maxlevels:
277edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            return "{...}", False, objid in context
278edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if objid in context:
279edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            return _recursion(object), False, True
280edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        context[objid] = 1
281edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        readable = True
282edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        recursive = False
283edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        components = []
284edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        append = components.append
285edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        level += 1
286edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        saferepr = _safe_repr
287edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for k, v in _sorted(object.items()):
288edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
289edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
290edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            append("%s: %s" % (krepr, vrepr))
291edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            readable = readable and kreadable and vreadable
292edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            if krecur or vrecur:
293edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                recursive = True
294edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        del context[objid]
295edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        return "{%s}" % _commajoin(components), readable, recursive
296edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
297edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    if (issubclass(typ, list) and r is list.__repr__) or \
298edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep       (issubclass(typ, tuple) and r is tuple.__repr__):
299edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if issubclass(typ, list):
300edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            if not object:
301edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                return "[]", True, False
302edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            format = "[%s]"
303edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        elif _len(object) == 1:
304edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            format = "(%s,)"
305edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        else:
306edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            if not object:
307edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                return "()", True, False
308edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            format = "(%s)"
309edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        objid = _id(object)
310edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if maxlevels and level >= maxlevels:
311edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            return format % "...", False, objid in context
312edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if objid in context:
313edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            return _recursion(object), False, True
314edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        context[objid] = 1
315edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        readable = True
316edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        recursive = False
317edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        components = []
318edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        append = components.append
319edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        level += 1
320edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for o in object:
321edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)
322edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            append(orepr)
323edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            if not oreadable:
324edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                readable = False
325edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            if orecur:
326edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                recursive = True
327edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        del context[objid]
328edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        return format % _commajoin(components), readable, recursive
329edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
330edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    rep = repr(object)
331edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    return rep, (rep and not rep.startswith('<')), False
332edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
333edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
334edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef _recursion(object):
335edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    return ("<Recursion on %s with id=%s>"
336edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            % (_type(object).__name__, _id(object)))
337edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
338edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
339edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef _perfcheck(object=None):
340edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    import time
341edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    if object is None:
342edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
343edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    p = PrettyPrinter()
344edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    t1 = time.time()
345edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    _safe_repr(object, {}, None, 0)
346edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    t2 = time.time()
347edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    p.pformat(object)
348edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    t3 = time.time()
349edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    print "_safe_repr:", t2 - t1
350edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    print "pformat:", t3 - t2
351edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
352edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepif __name__ == "__main__":
353edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    _perfcheck()
354