872 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			872 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # -*- coding: utf-8 -*-
 | |
| """
 | |
| Python advanced pretty printer.  This pretty printer is intended to
 | |
| replace the old `pprint` python module which does not allow developers
 | |
| to provide their own pretty print callbacks.
 | |
| 
 | |
| This module is based on ruby's `prettyprint.rb` library by `Tanaka Akira`.
 | |
| 
 | |
| 
 | |
| Example Usage
 | |
| -------------
 | |
| 
 | |
| To directly print the representation of an object use `pprint`::
 | |
| 
 | |
|     from pretty import pprint
 | |
|     pprint(complex_object)
 | |
| 
 | |
| To get a string of the output use `pretty`::
 | |
| 
 | |
|     from pretty import pretty
 | |
|     string = pretty(complex_object)
 | |
| 
 | |
| 
 | |
| Extending
 | |
| ---------
 | |
| 
 | |
| The pretty library allows developers to add pretty printing rules for their
 | |
| own objects.  This process is straightforward.  All you have to do is to
 | |
| add a `_repr_pretty_` method to your object and call the methods on the
 | |
| pretty printer passed::
 | |
| 
 | |
|     class MyObject(object):
 | |
| 
 | |
|         def _repr_pretty_(self, p, cycle):
 | |
|             ...
 | |
| 
 | |
| Here is an example implementation of a `_repr_pretty_` method for a list
 | |
| subclass::
 | |
| 
 | |
|     class MyList(list):
 | |
| 
 | |
|         def _repr_pretty_(self, p, cycle):
 | |
|             if cycle:
 | |
|                 p.text('MyList(...)')
 | |
|             else:
 | |
|                 with p.group(8, 'MyList([', '])'):
 | |
|                     for idx, item in enumerate(self):
 | |
|                         if idx:
 | |
|                             p.text(',')
 | |
|                             p.breakable()
 | |
|                         p.pretty(item)
 | |
| 
 | |
| The `cycle` parameter is `True` if pretty detected a cycle.  You *have* to
 | |
| react to that or the result is an infinite loop.  `p.text()` just adds
 | |
| non breaking text to the output, `p.breakable()` either adds a whitespace
 | |
| or breaks here.  If you pass it an argument it's used instead of the
 | |
| default space.  `p.pretty` prettyprints another object using the pretty print
 | |
| method.
 | |
| 
 | |
| The first parameter to the `group` function specifies the extra indentation
 | |
| of the next line.  In this example the next item will either be on the same
 | |
| line (if the items are short enough) or aligned with the right edge of the
 | |
| opening bracket of `MyList`.
 | |
| 
 | |
| If you just want to indent something you can use the group function
 | |
| without open / close parameters.  You can also use this code::
 | |
| 
 | |
|     with p.indent(2):
 | |
|         ...
 | |
| 
 | |
| Inheritance diagram:
 | |
| 
 | |
| .. inheritance-diagram:: yap_ipython.lib.pretty
 | |
|    :parts: 3
 | |
| 
 | |
| :copyright: 2007 by Armin Ronacher.
 | |
|             Portions (c) 2009 by Robert Kern.
 | |
| :license: BSD License.
 | |
| """
 | |
| from contextlib import contextmanager
 | |
| import sys
 | |
| import types
 | |
| import re
 | |
| import datetime
 | |
| from collections import deque
 | |
| from io import StringIO
 | |
| from warnings import warn
 | |
| 
 | |
| from yap_ipython.utils.decorators import undoc
 | |
| from yap_ipython.utils.py3compat import PYPY
 | |
| from yap_ipython.utils.signatures import signature
 | |
| 
 | |
| __all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter',
 | |
|     'for_type', 'for_type_by_name']
 | |
| 
 | |
| 
 | |
| MAX_SEQ_LENGTH = 1000
 | |
| _re_pattern_type = type(re.compile(''))
 | |
| 
 | |
| def _safe_getattr(obj, attr, default=None):
 | |
|     """Safe version of getattr.
 | |
|     
 | |
|     Same as getattr, but will return ``default`` on any Exception,
 | |
|     rather than raising.
 | |
|     """
 | |
|     try:
 | |
|         return getattr(obj, attr, default)
 | |
|     except Exception:
 | |
|         return default
 | |
| 
 | |
| @undoc
 | |
| class CUnicodeIO(StringIO):
 | |
|     def __init__(self, *args, **kwargs):
 | |
|         super().__init__(*args, **kwargs)
 | |
|         warn(("CUnicodeIO is deprecated since yap_ipython 6.0. "
 | |
|               "Please use io.StringIO instead."),
 | |
|              DeprecationWarning, stacklevel=2)
 | |
| 
 | |
| def _sorted_for_pprint(items):
 | |
|     """
 | |
|     Sort the given items for pretty printing. Since some predictable
 | |
|     sorting is better than no sorting at all, we sort on the string
 | |
|     representation if normal sorting fails.
 | |
|     """
 | |
|     items = list(items)
 | |
|     try:
 | |
|         return sorted(items)
 | |
|     except Exception:
 | |
|         try:
 | |
|             return sorted(items, key=str)
 | |
|         except Exception:
 | |
|             return items
 | |
| 
 | |
| def pretty(obj, verbose=False, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
 | |
|     """
 | |
|     Pretty print the object's representation.
 | |
|     """
 | |
|     stream = StringIO()
 | |
|     printer = RepresentationPrinter(stream, verbose, max_width, newline, max_seq_length=max_seq_length)
 | |
|     printer.pretty(obj)
 | |
|     printer.flush()
 | |
|     return stream.getvalue()
 | |
| 
 | |
| 
 | |
| def pprint(obj, verbose=False, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
 | |
|     """
 | |
|     Like `pretty` but print to stdout.
 | |
|     """
 | |
|     printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline, max_seq_length=max_seq_length)
 | |
|     printer.pretty(obj)
 | |
|     printer.flush()
 | |
|     sys.stdout.write(newline)
 | |
|     sys.stdout.flush()
 | |
| 
 | |
| class _PrettyPrinterBase(object):
 | |
| 
 | |
|     @contextmanager
 | |
|     def indent(self, indent):
 | |
|         """with statement support for indenting/dedenting."""
 | |
|         self.indentation += indent
 | |
|         try:
 | |
|             yield
 | |
|         finally:
 | |
|             self.indentation -= indent
 | |
| 
 | |
|     @contextmanager
 | |
|     def group(self, indent=0, open='', close=''):
 | |
|         """like begin_group / end_group but for the with statement."""
 | |
|         self.begin_group(indent, open)
 | |
|         try:
 | |
|             yield
 | |
|         finally:
 | |
|             self.end_group(indent, close)
 | |
| 
 | |
| class PrettyPrinter(_PrettyPrinterBase):
 | |
|     """
 | |
|     Baseclass for the `RepresentationPrinter` prettyprinter that is used to
 | |
|     generate pretty reprs of objects.  Contrary to the `RepresentationPrinter`
 | |
|     this printer knows nothing about the default pprinters or the `_repr_pretty_`
 | |
|     callback method.
 | |
|     """
 | |
| 
 | |
|     def __init__(self, output, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
 | |
|         self.output = output
 | |
|         self.max_width = max_width
 | |
|         self.newline = newline
 | |
|         self.max_seq_length = max_seq_length
 | |
|         self.output_width = 0
 | |
|         self.buffer_width = 0
 | |
|         self.buffer = deque()
 | |
| 
 | |
|         root_group = Group(0)
 | |
|         self.group_stack = [root_group]
 | |
|         self.group_queue = GroupQueue(root_group)
 | |
|         self.indentation = 0
 | |
| 
 | |
|     def _break_outer_groups(self):
 | |
|         while self.max_width < self.output_width + self.buffer_width:
 | |
|             group = self.group_queue.deq()
 | |
|             if not group:
 | |
|                 return
 | |
|             while group.breakables:
 | |
|                 x = self.buffer.popleft()
 | |
|                 self.output_width = x.output(self.output, self.output_width)
 | |
|                 self.buffer_width -= x.width
 | |
|             while self.buffer and isinstance(self.buffer[0], Text):
 | |
|                 x = self.buffer.popleft()
 | |
|                 self.output_width = x.output(self.output, self.output_width)
 | |
|                 self.buffer_width -= x.width
 | |
| 
 | |
|     def text(self, obj):
 | |
|         """Add literal text to the output."""
 | |
|         width = len(obj)
 | |
|         if self.buffer:
 | |
|             text = self.buffer[-1]
 | |
|             if not isinstance(text, Text):
 | |
|                 text = Text()
 | |
|                 self.buffer.append(text)
 | |
|             text.add(obj, width)
 | |
|             self.buffer_width += width
 | |
|             self._break_outer_groups()
 | |
|         else:
 | |
|             self.output.write(obj)
 | |
|             self.output_width += width
 | |
| 
 | |
|     def breakable(self, sep=' '):
 | |
|         """
 | |
|         Add a breakable separator to the output.  This does not mean that it
 | |
|         will automatically break here.  If no breaking on this position takes
 | |
|         place the `sep` is inserted which default to one space.
 | |
|         """
 | |
|         width = len(sep)
 | |
|         group = self.group_stack[-1]
 | |
|         if group.want_break:
 | |
|             self.flush()
 | |
|             self.output.write(self.newline)
 | |
|             self.output.write(' ' * self.indentation)
 | |
|             self.output_width = self.indentation
 | |
|             self.buffer_width = 0
 | |
|         else:
 | |
|             self.buffer.append(Breakable(sep, width, self))
 | |
|             self.buffer_width += width
 | |
|             self._break_outer_groups()
 | |
|             
 | |
|     def break_(self):
 | |
|         """
 | |
|         Explicitly insert a newline into the output, maintaining correct indentation.
 | |
|         """
 | |
|         self.flush()
 | |
|         self.output.write(self.newline)
 | |
|         self.output.write(' ' * self.indentation)
 | |
|         self.output_width = self.indentation
 | |
|         self.buffer_width = 0
 | |
|         
 | |
| 
 | |
|     def begin_group(self, indent=0, open=''):
 | |
|         """
 | |
|         Begin a group.  If you want support for python < 2.5 which doesn't has
 | |
|         the with statement this is the preferred way:
 | |
| 
 | |
|             p.begin_group(1, '{')
 | |
|             ...
 | |
|             p.end_group(1, '}')
 | |
| 
 | |
|         The python 2.5 expression would be this:
 | |
| 
 | |
|             with p.group(1, '{', '}'):
 | |
|                 ...
 | |
| 
 | |
|         The first parameter specifies the indentation for the next line (usually
 | |
|         the width of the opening text), the second the opening text.  All
 | |
|         parameters are optional.
 | |
|         """
 | |
|         if open:
 | |
|             self.text(open)
 | |
|         group = Group(self.group_stack[-1].depth + 1)
 | |
|         self.group_stack.append(group)
 | |
|         self.group_queue.enq(group)
 | |
|         self.indentation += indent
 | |
|     
 | |
|     def _enumerate(self, seq):
 | |
|         """like enumerate, but with an upper limit on the number of items"""
 | |
|         for idx, x in enumerate(seq):
 | |
|             if self.max_seq_length and idx >= self.max_seq_length:
 | |
|                 self.text(',')
 | |
|                 self.breakable()
 | |
|                 self.text('...')
 | |
|                 return
 | |
|             yield idx, x
 | |
|     
 | |
|     def end_group(self, dedent=0, close=''):
 | |
|         """End a group. See `begin_group` for more details."""
 | |
|         self.indentation -= dedent
 | |
|         group = self.group_stack.pop()
 | |
|         if not group.breakables:
 | |
|             self.group_queue.remove(group)
 | |
|         if close:
 | |
|             self.text(close)
 | |
| 
 | |
|     def flush(self):
 | |
|         """Flush data that is left in the buffer."""
 | |
|         for data in self.buffer:
 | |
|             self.output_width += data.output(self.output, self.output_width)
 | |
|         self.buffer.clear()
 | |
|         self.buffer_width = 0
 | |
| 
 | |
| 
 | |
| def _get_mro(obj_class):
 | |
|     """ Get a reasonable method resolution order of a class and its superclasses
 | |
|     for both old-style and new-style classes.
 | |
|     """
 | |
|     if not hasattr(obj_class, '__mro__'):
 | |
|         # Old-style class. Mix in object to make a fake new-style class.
 | |
|         try:
 | |
|             obj_class = type(obj_class.__name__, (obj_class, object), {})
 | |
|         except TypeError:
 | |
|             # Old-style extension type that does not descend from object.
 | |
|             # FIXME: try to construct a more thorough MRO.
 | |
|             mro = [obj_class]
 | |
|         else:
 | |
|             mro = obj_class.__mro__[1:-1]
 | |
|     else:
 | |
|         mro = obj_class.__mro__
 | |
|     return mro
 | |
| 
 | |
| 
 | |
| class RepresentationPrinter(PrettyPrinter):
 | |
|     """
 | |
|     Special pretty printer that has a `pretty` method that calls the pretty
 | |
|     printer for a python object.
 | |
| 
 | |
|     This class stores processing data on `self` so you must *never* use
 | |
|     this class in a threaded environment.  Always lock it or reinstanciate
 | |
|     it.
 | |
| 
 | |
|     Instances also have a verbose flag callbacks can access to control their
 | |
|     output.  For example the default instance repr prints all attributes and
 | |
|     methods that are not prefixed by an underscore if the printer is in
 | |
|     verbose mode.
 | |
|     """
 | |
| 
 | |
|     def __init__(self, output, verbose=False, max_width=79, newline='\n',
 | |
|         singleton_pprinters=None, type_pprinters=None, deferred_pprinters=None,
 | |
|         max_seq_length=MAX_SEQ_LENGTH):
 | |
| 
 | |
|         PrettyPrinter.__init__(self, output, max_width, newline, max_seq_length=max_seq_length)
 | |
|         self.verbose = verbose
 | |
|         self.stack = []
 | |
|         if singleton_pprinters is None:
 | |
|             singleton_pprinters = _singleton_pprinters.copy()
 | |
|         self.singleton_pprinters = singleton_pprinters
 | |
|         if type_pprinters is None:
 | |
|             type_pprinters = _type_pprinters.copy()
 | |
|         self.type_pprinters = type_pprinters
 | |
|         if deferred_pprinters is None:
 | |
|             deferred_pprinters = _deferred_type_pprinters.copy()
 | |
|         self.deferred_pprinters = deferred_pprinters
 | |
| 
 | |
|     def pretty(self, obj):
 | |
|         """Pretty print the given object."""
 | |
|         obj_id = id(obj)
 | |
|         cycle = obj_id in self.stack
 | |
|         self.stack.append(obj_id)
 | |
|         self.begin_group()
 | |
|         try:
 | |
|             obj_class = _safe_getattr(obj, '__class__', None) or type(obj)
 | |
|             # First try to find registered singleton printers for the type.
 | |
|             try:
 | |
|                 printer = self.singleton_pprinters[obj_id]
 | |
|             except (TypeError, KeyError):
 | |
|                 pass
 | |
|             else:
 | |
|                 return printer(obj, self, cycle)
 | |
|             # Next walk the mro and check for either:
 | |
|             #   1) a registered printer
 | |
|             #   2) a _repr_pretty_ method
 | |
|             for cls in _get_mro(obj_class):
 | |
|                 if cls in self.type_pprinters:
 | |
|                     # printer registered in self.type_pprinters
 | |
|                     return self.type_pprinters[cls](obj, self, cycle)
 | |
|                 else:
 | |
|                     # deferred printer
 | |
|                     printer = self._in_deferred_types(cls)
 | |
|                     if printer is not None:
 | |
|                         return printer(obj, self, cycle)
 | |
|                     else:
 | |
|                         # Finally look for special method names.
 | |
|                         # Some objects automatically create any requested
 | |
|                         # attribute. Try to ignore most of them by checking for
 | |
|                         # callability.
 | |
|                         if '_repr_pretty_' in cls.__dict__:
 | |
|                             meth = cls._repr_pretty_
 | |
|                             if callable(meth):
 | |
|                                 return meth(obj, self, cycle)
 | |
|             return _default_pprint(obj, self, cycle)
 | |
|         finally:
 | |
|             self.end_group()
 | |
|             self.stack.pop()
 | |
| 
 | |
|     def _in_deferred_types(self, cls):
 | |
|         """
 | |
|         Check if the given class is specified in the deferred type registry.
 | |
| 
 | |
|         Returns the printer from the registry if it exists, and None if the
 | |
|         class is not in the registry. Successful matches will be moved to the
 | |
|         regular type registry for future use.
 | |
|         """
 | |
|         mod = _safe_getattr(cls, '__module__', None)
 | |
|         name = _safe_getattr(cls, '__name__', None)
 | |
|         key = (mod, name)
 | |
|         printer = None
 | |
|         if key in self.deferred_pprinters:
 | |
|             # Move the printer over to the regular registry.
 | |
|             printer = self.deferred_pprinters.pop(key)
 | |
|             self.type_pprinters[cls] = printer
 | |
|         return printer
 | |
| 
 | |
| 
 | |
| class Printable(object):
 | |
| 
 | |
|     def output(self, stream, output_width):
 | |
|         return output_width
 | |
| 
 | |
| 
 | |
| class Text(Printable):
 | |
| 
 | |
|     def __init__(self):
 | |
|         self.objs = []
 | |
|         self.width = 0
 | |
| 
 | |
|     def output(self, stream, output_width):
 | |
|         for obj in self.objs:
 | |
|             stream.write(obj)
 | |
|         return output_width + self.width
 | |
| 
 | |
|     def add(self, obj, width):
 | |
|         self.objs.append(obj)
 | |
|         self.width += width
 | |
| 
 | |
| 
 | |
| class Breakable(Printable):
 | |
| 
 | |
|     def __init__(self, seq, width, pretty):
 | |
|         self.obj = seq
 | |
|         self.width = width
 | |
|         self.pretty = pretty
 | |
|         self.indentation = pretty.indentation
 | |
|         self.group = pretty.group_stack[-1]
 | |
|         self.group.breakables.append(self)
 | |
| 
 | |
|     def output(self, stream, output_width):
 | |
|         self.group.breakables.popleft()
 | |
|         if self.group.want_break:
 | |
|             stream.write(self.pretty.newline)
 | |
|             stream.write(' ' * self.indentation)
 | |
|             return self.indentation
 | |
|         if not self.group.breakables:
 | |
|             self.pretty.group_queue.remove(self.group)
 | |
|         stream.write(self.obj)
 | |
|         return output_width + self.width
 | |
| 
 | |
| 
 | |
| class Group(Printable):
 | |
| 
 | |
|     def __init__(self, depth):
 | |
|         self.depth = depth
 | |
|         self.breakables = deque()
 | |
|         self.want_break = False
 | |
| 
 | |
| 
 | |
| class GroupQueue(object):
 | |
| 
 | |
|     def __init__(self, *groups):
 | |
|         self.queue = []
 | |
|         for group in groups:
 | |
|             self.enq(group)
 | |
| 
 | |
|     def enq(self, group):
 | |
|         depth = group.depth
 | |
|         while depth > len(self.queue) - 1:
 | |
|             self.queue.append([])
 | |
|         self.queue[depth].append(group)
 | |
| 
 | |
|     def deq(self):
 | |
|         for stack in self.queue:
 | |
|             for idx, group in enumerate(reversed(stack)):
 | |
|                 if group.breakables:
 | |
|                     del stack[idx]
 | |
|                     group.want_break = True
 | |
|                     return group
 | |
|             for group in stack:
 | |
|                 group.want_break = True
 | |
|             del stack[:]
 | |
| 
 | |
|     def remove(self, group):
 | |
|         try:
 | |
|             self.queue[group.depth].remove(group)
 | |
|         except ValueError:
 | |
|             pass
 | |
| 
 | |
| 
 | |
| def _default_pprint(obj, p, cycle):
 | |
|     """
 | |
|     The default print function.  Used if an object does not provide one and
 | |
|     it's none of the builtin objects.
 | |
|     """
 | |
|     klass = _safe_getattr(obj, '__class__', None) or type(obj)
 | |
|     if _safe_getattr(klass, '__repr__', None) is not object.__repr__:
 | |
|         # A user-provided repr. Find newlines and replace them with p.break_()
 | |
|         _repr_pprint(obj, p, cycle)
 | |
|         return
 | |
|     p.begin_group(1, '<')
 | |
|     p.pretty(klass)
 | |
|     p.text(' at 0x%x' % id(obj))
 | |
|     if cycle:
 | |
|         p.text(' ...')
 | |
|     elif p.verbose:
 | |
|         first = True
 | |
|         for key in dir(obj):
 | |
|             if not key.startswith('_'):
 | |
|                 try:
 | |
|                     value = getattr(obj, key)
 | |
|                 except AttributeError:
 | |
|                     continue
 | |
|                 if isinstance(value, types.MethodType):
 | |
|                     continue
 | |
|                 if not first:
 | |
|                     p.text(',')
 | |
|                 p.breakable()
 | |
|                 p.text(key)
 | |
|                 p.text('=')
 | |
|                 step = len(key) + 1
 | |
|                 p.indentation += step
 | |
|                 p.pretty(value)
 | |
|                 p.indentation -= step
 | |
|                 first = False
 | |
|     p.end_group(1, '>')
 | |
| 
 | |
| 
 | |
| def _seq_pprinter_factory(start, end, basetype):
 | |
|     """
 | |
|     Factory that returns a pprint function useful for sequences.  Used by
 | |
|     the default pprint for tuples, dicts, and lists.
 | |
|     """
 | |
|     def inner(obj, p, cycle):
 | |
|         typ = type(obj)
 | |
|         if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
 | |
|             # If the subclass provides its own repr, use it instead.
 | |
|             return p.text(typ.__repr__(obj))
 | |
| 
 | |
|         if cycle:
 | |
|             return p.text(start + '...' + end)
 | |
|         step = len(start)
 | |
|         p.begin_group(step, start)
 | |
|         for idx, x in p._enumerate(obj):
 | |
|             if idx:
 | |
|                 p.text(',')
 | |
|                 p.breakable()
 | |
|             p.pretty(x)
 | |
|         if len(obj) == 1 and type(obj) is tuple:
 | |
|             # Special case for 1-item tuples.
 | |
|             p.text(',')
 | |
|         p.end_group(step, end)
 | |
|     return inner
 | |
| 
 | |
| 
 | |
| def _set_pprinter_factory(start, end, basetype):
 | |
|     """
 | |
|     Factory that returns a pprint function useful for sets and frozensets.
 | |
|     """
 | |
|     def inner(obj, p, cycle):
 | |
|         typ = type(obj)
 | |
|         if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
 | |
|             # If the subclass provides its own repr, use it instead.
 | |
|             return p.text(typ.__repr__(obj))
 | |
| 
 | |
|         if cycle:
 | |
|             return p.text(start + '...' + end)
 | |
|         if len(obj) == 0:
 | |
|             # Special case.
 | |
|             p.text(basetype.__name__ + '()')
 | |
|         else:
 | |
|             step = len(start)
 | |
|             p.begin_group(step, start)
 | |
|             # Like dictionary keys, we will try to sort the items if there aren't too many
 | |
|             if not (p.max_seq_length and len(obj) >= p.max_seq_length):
 | |
|                 items = _sorted_for_pprint(obj)
 | |
|             else:
 | |
|                 items = obj
 | |
|             for idx, x in p._enumerate(items):
 | |
|                 if idx:
 | |
|                     p.text(',')
 | |
|                     p.breakable()
 | |
|                 p.pretty(x)
 | |
|             p.end_group(step, end)
 | |
|     return inner
 | |
| 
 | |
| 
 | |
| def _dict_pprinter_factory(start, end, basetype=None):
 | |
|     """
 | |
|     Factory that returns a pprint function used by the default pprint of
 | |
|     dicts and dict proxies.
 | |
|     """
 | |
|     def inner(obj, p, cycle):
 | |
|         typ = type(obj)
 | |
|         if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
 | |
|             # If the subclass provides its own repr, use it instead.
 | |
|             return p.text(typ.__repr__(obj))
 | |
| 
 | |
|         if cycle:
 | |
|             return p.text('{...}')
 | |
|         step = len(start)
 | |
|         p.begin_group(step, start)
 | |
|         keys = obj.keys()
 | |
|         # if dict isn't large enough to be truncated, sort keys before displaying
 | |
|         if not (p.max_seq_length and len(obj) >= p.max_seq_length):
 | |
|             keys = _sorted_for_pprint(keys)
 | |
|         for idx, key in p._enumerate(keys):
 | |
|             if idx:
 | |
|                 p.text(',')
 | |
|                 p.breakable()
 | |
|             p.pretty(key)
 | |
|             p.text(': ')
 | |
|             p.pretty(obj[key])
 | |
|         p.end_group(step, end)
 | |
|     return inner
 | |
| 
 | |
| 
 | |
| def _super_pprint(obj, p, cycle):
 | |
|     """The pprint for the super type."""
 | |
|     p.begin_group(8, '<super: ')
 | |
|     p.pretty(obj.__thisclass__)
 | |
|     p.text(',')
 | |
|     p.breakable()
 | |
|     if PYPY: # In PyPy, super() objects don't have __self__ attributes
 | |
|         dself = obj.__repr__.__self__
 | |
|         p.pretty(None if dself is obj else dself)
 | |
|     else:
 | |
|         p.pretty(obj.__self__)
 | |
|     p.end_group(8, '>')
 | |
| 
 | |
| 
 | |
| def _re_pattern_pprint(obj, p, cycle):
 | |
|     """The pprint function for regular expression patterns."""
 | |
|     p.text('re.compile(')
 | |
|     pattern = repr(obj.pattern)
 | |
|     if pattern[:1] in 'uU':
 | |
|         pattern = pattern[1:]
 | |
|         prefix = 'ur'
 | |
|     else:
 | |
|         prefix = 'r'
 | |
|     pattern = prefix + pattern.replace('\\\\', '\\')
 | |
|     p.text(pattern)
 | |
|     if obj.flags:
 | |
|         p.text(',')
 | |
|         p.breakable()
 | |
|         done_one = False
 | |
|         for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL',
 | |
|             'UNICODE', 'VERBOSE', 'DEBUG'):
 | |
|             if obj.flags & getattr(re, flag):
 | |
|                 if done_one:
 | |
|                     p.text('|')
 | |
|                 p.text('re.' + flag)
 | |
|                 done_one = True
 | |
|     p.text(')')
 | |
| 
 | |
| 
 | |
| def _type_pprint(obj, p, cycle):
 | |
|     """The pprint for classes and types."""
 | |
|     # Heap allocated types might not have the module attribute,
 | |
|     # and others may set it to None.
 | |
| 
 | |
|     # Checks for a __repr__ override in the metaclass. Can't compare the
 | |
|     # type(obj).__repr__ directly because in PyPy the representation function
 | |
|     # inherited from type isn't the same type.__repr__
 | |
|     if [m for m in _get_mro(type(obj)) if "__repr__" in vars(m)][:1] != [type]:
 | |
|         _repr_pprint(obj, p, cycle)
 | |
|         return
 | |
| 
 | |
|     mod = _safe_getattr(obj, '__module__', None)
 | |
|     try:
 | |
|         name = obj.__qualname__
 | |
|         if not isinstance(name, str):
 | |
|             # This can happen if the type implements __qualname__ as a property
 | |
|             # or other descriptor in Python 2.
 | |
|             raise Exception("Try __name__")
 | |
|     except Exception:
 | |
|         name = obj.__name__
 | |
|         if not isinstance(name, str):
 | |
|             name = '<unknown type>'
 | |
| 
 | |
|     if mod in (None, '__builtin__', 'builtins', 'exceptions'):
 | |
|         p.text(name)
 | |
|     else:
 | |
|         p.text(mod + '.' + name)
 | |
| 
 | |
| 
 | |
| def _repr_pprint(obj, p, cycle):
 | |
|     """A pprint that just redirects to the normal repr function."""
 | |
|     # Find newlines and replace them with p.break_()
 | |
|     output = repr(obj)
 | |
|     for idx,output_line in enumerate(output.splitlines()):
 | |
|         if idx:
 | |
|             p.break_()
 | |
|         p.text(output_line)
 | |
| 
 | |
| 
 | |
| def _function_pprint(obj, p, cycle):
 | |
|     """Base pprint for all functions and builtin functions."""
 | |
|     name = _safe_getattr(obj, '__qualname__', obj.__name__)
 | |
|     mod = obj.__module__
 | |
|     if mod and mod not in ('__builtin__', 'builtins', 'exceptions'):
 | |
|         name = mod + '.' + name
 | |
|     try:
 | |
|        func_def = name + str(signature(obj))
 | |
|     except ValueError:
 | |
|        func_def = name
 | |
|     p.text('<function %s>' % func_def)
 | |
| 
 | |
| 
 | |
| def _exception_pprint(obj, p, cycle):
 | |
|     """Base pprint for all exceptions."""
 | |
|     name = getattr(obj.__class__, '__qualname__', obj.__class__.__name__)
 | |
|     if obj.__class__.__module__ not in ('exceptions', 'builtins'):
 | |
|         name = '%s.%s' % (obj.__class__.__module__, name)
 | |
|     step = len(name) + 1
 | |
|     p.begin_group(step, name + '(')
 | |
|     for idx, arg in enumerate(getattr(obj, 'args', ())):
 | |
|         if idx:
 | |
|             p.text(',')
 | |
|             p.breakable()
 | |
|         p.pretty(arg)
 | |
|     p.end_group(step, ')')
 | |
| 
 | |
| 
 | |
| #: the exception base
 | |
| try:
 | |
|     _exception_base = BaseException
 | |
| except NameError:
 | |
|     _exception_base = Exception
 | |
| 
 | |
| 
 | |
| #: printers for builtin types
 | |
| _type_pprinters = {
 | |
|     int:                        _repr_pprint,
 | |
|     float:                      _repr_pprint,
 | |
|     str:                        _repr_pprint,
 | |
|     tuple:                      _seq_pprinter_factory('(', ')', tuple),
 | |
|     list:                       _seq_pprinter_factory('[', ']', list),
 | |
|     dict:                       _dict_pprinter_factory('{', '}', dict),
 | |
|     
 | |
|     set:                        _set_pprinter_factory('{', '}', set),
 | |
|     frozenset:                  _set_pprinter_factory('frozenset({', '})', frozenset),
 | |
|     super:                      _super_pprint,
 | |
|     _re_pattern_type:           _re_pattern_pprint,
 | |
|     type:                       _type_pprint,
 | |
|     types.FunctionType:         _function_pprint,
 | |
|     types.BuiltinFunctionType:  _function_pprint,
 | |
|     types.MethodType:           _repr_pprint,
 | |
|     
 | |
|     datetime.datetime:          _repr_pprint,
 | |
|     datetime.timedelta:         _repr_pprint,
 | |
|     _exception_base:            _exception_pprint
 | |
| }
 | |
| 
 | |
| try:
 | |
|     # In PyPy, types.DictProxyType is dict, setting the dictproxy printer
 | |
|     # using dict.setdefault avoids overwritting the dict printer
 | |
|     _type_pprinters.setdefault(types.DictProxyType,
 | |
|                                _dict_pprinter_factory('dict_proxy({', '})'))
 | |
|     _type_pprinters[types.ClassType] = _type_pprint
 | |
|     _type_pprinters[types.SliceType] = _repr_pprint
 | |
| except AttributeError: # Python 3
 | |
|     _type_pprinters[types.MappingProxyType] = \
 | |
|         _dict_pprinter_factory('mappingproxy({', '})')
 | |
|     _type_pprinters[slice] = _repr_pprint
 | |
|     
 | |
| try:
 | |
|     _type_pprinters[long] = _repr_pprint
 | |
|     _type_pprinters[unicode] = _repr_pprint
 | |
| except NameError:
 | |
|     _type_pprinters[range] = _repr_pprint
 | |
|     _type_pprinters[bytes] = _repr_pprint
 | |
| 
 | |
| #: printers for types specified by name
 | |
| _deferred_type_pprinters = {
 | |
| }
 | |
| 
 | |
| def for_type(typ, func):
 | |
|     """
 | |
|     Add a pretty printer for a given type.
 | |
|     """
 | |
|     oldfunc = _type_pprinters.get(typ, None)
 | |
|     if func is not None:
 | |
|         # To support easy restoration of old pprinters, we need to ignore Nones.
 | |
|         _type_pprinters[typ] = func
 | |
|     return oldfunc
 | |
| 
 | |
| def for_type_by_name(type_module, type_name, func):
 | |
|     """
 | |
|     Add a pretty printer for a type specified by the module and name of a type
 | |
|     rather than the type object itself.
 | |
|     """
 | |
|     key = (type_module, type_name)
 | |
|     oldfunc = _deferred_type_pprinters.get(key, None)
 | |
|     if func is not None:
 | |
|         # To support easy restoration of old pprinters, we need to ignore Nones.
 | |
|         _deferred_type_pprinters[key] = func
 | |
|     return oldfunc
 | |
| 
 | |
| 
 | |
| #: printers for the default singletons
 | |
| _singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis,
 | |
|                                       NotImplemented]), _repr_pprint)
 | |
| 
 | |
| 
 | |
| def _defaultdict_pprint(obj, p, cycle):
 | |
|     name = obj.__class__.__name__
 | |
|     with p.group(len(name) + 1, name + '(', ')'):
 | |
|         if cycle:
 | |
|             p.text('...')
 | |
|         else:
 | |
|             p.pretty(obj.default_factory)
 | |
|             p.text(',')
 | |
|             p.breakable()
 | |
|             p.pretty(dict(obj))
 | |
| 
 | |
| def _ordereddict_pprint(obj, p, cycle):
 | |
|     name = obj.__class__.__name__
 | |
|     with p.group(len(name) + 1, name + '(', ')'):
 | |
|         if cycle:
 | |
|             p.text('...')
 | |
|         elif len(obj):
 | |
|             p.pretty(list(obj.items()))
 | |
| 
 | |
| def _deque_pprint(obj, p, cycle):
 | |
|     name = obj.__class__.__name__
 | |
|     with p.group(len(name) + 1, name + '(', ')'):
 | |
|         if cycle:
 | |
|             p.text('...')
 | |
|         else:
 | |
|             p.pretty(list(obj))
 | |
| 
 | |
| 
 | |
| def _counter_pprint(obj, p, cycle):
 | |
|     name = obj.__class__.__name__
 | |
|     with p.group(len(name) + 1, name + '(', ')'):
 | |
|         if cycle:
 | |
|             p.text('...')
 | |
|         elif len(obj):
 | |
|             p.pretty(dict(obj))
 | |
| 
 | |
| for_type_by_name('collections', 'defaultdict', _defaultdict_pprint)
 | |
| for_type_by_name('collections', 'OrderedDict', _ordereddict_pprint)
 | |
| for_type_by_name('collections', 'deque', _deque_pprint)
 | |
| for_type_by_name('collections', 'Counter', _counter_pprint)
 | |
| 
 | |
| if __name__ == '__main__':
 | |
|     from random import randrange
 | |
|     class Foo(object):
 | |
|         def __init__(self):
 | |
|             self.foo = 1
 | |
|             self.bar = re.compile(r'\s+')
 | |
|             self.blub = dict.fromkeys(range(30), randrange(1, 40))
 | |
|             self.hehe = 23424.234234
 | |
|             self.list = ["blub", "blah", self]
 | |
| 
 | |
|         def get_foo(self):
 | |
|             print("foo")
 | |
| 
 | |
|     pprint(Foo(), verbose=True)
 |