pretty.py
856 lines
| 26.8 KiB
| text/x-python
|
PythonLexer
Robert Kern
|
r1831 | # -*- coding: utf-8 -*- | ||
""" | ||||
Thomas Kluyver
|
r8795 | 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. | ||||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | This module is based on ruby's `prettyprint.rb` library by `Tanaka Akira`. | ||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | Example Usage | ||
------------- | ||||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | To directly print the representation of an object use `pprint`:: | ||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | from pretty import pprint | ||
pprint(complex_object) | ||||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | To get a string of the output use `pretty`:: | ||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | from pretty import pretty | ||
string = pretty(complex_object) | ||||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | Extending | ||
--------- | ||||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | 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:: | ||||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | class MyObject(object): | ||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | def _repr_pretty_(self, p, cycle): | ||
... | ||||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | Depending on the python version you want to support you have two | ||
possibilities. The following list shows the python 2.5 version and the | ||||
compatibility one. | ||||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | Here the example implementation of a `_repr_pretty_` method for a list | ||
subclass for python 2.5 and higher (python 2.5 requires the with statement | ||||
__future__ import):: | ||||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | class MyList(list): | ||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | 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) | ||||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | 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. | ||||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | The first parameter to the `group` function specifies the extra indentation | ||
of the next line. In this example the next item will either be not | ||||
breaked (if the items are short enough) or aligned with the right edge of | ||||
the opening bracked of `MyList`. | ||||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | If you want to support python 2.4 and lower you can use this code:: | ||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | class MyList(list): | ||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | def _repr_pretty_(self, p, cycle): | ||
if cycle: | ||||
p.text('MyList(...)') | ||||
else: | ||||
p.begin_group(8, 'MyList([') | ||||
for idx, item in enumerate(self): | ||||
if idx: | ||||
p.text(',') | ||||
p.breakable() | ||||
p.pretty(item) | ||||
p.end_group(8, '])') | ||||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | If you just want to indent something you can use the group function | ||
without open / close parameters. Under python 2.5 you can also use this | ||||
code:: | ||||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | with p.indent(2): | ||
... | ||||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | Or under python2.4 you might want to modify ``p.indentation`` by hand but | ||
this is rather ugly. | ||||
Inheritance diagram: | ||||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | .. inheritance-diagram:: IPython.lib.pretty | ||
:parts: 3 | ||||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | :copyright: 2007 by Armin Ronacher. | ||
Portions (c) 2009 by Robert Kern. | ||||
:license: BSD License. | ||||
Robert Kern
|
r1831 | """ | ||
Thomas Kluyver
|
r13348 | from __future__ import print_function | ||
Thomas Kluyver
|
r3115 | from contextlib import contextmanager | ||
Robert Kern
|
r1831 | import sys | ||
import types | ||||
import re | ||||
import datetime | ||||
from collections import deque | ||||
Thomas Kluyver
|
r13366 | from IPython.utils.py3compat import PY3 | ||
if PY3: | ||||
from io import StringIO | ||||
else: | ||||
from StringIO import StringIO | ||||
Robert Kern
|
r1831 | |||
__all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter', | ||||
'for_type', 'for_type_by_name'] | ||||
MinRK
|
r15852 | |||
Robert Kern
|
r1831 | _re_pattern_type = type(re.compile('')) | ||
MinRK
|
r13430 | def _failed_repr(obj, e): | ||
"""Render a failed repr, including the exception. | ||||
Tries to get exception and type info | ||||
""" | ||||
# get exception name | ||||
if e.__class__.__module__ in ('exceptions', 'builtins'): | ||||
ename = e.__class__.__name__ | ||||
else: | ||||
ename = '{}.{}'.format( | ||||
e.__class__.__module__, | ||||
e.__class__.__name__, | ||||
) | ||||
# and exception string, which sometimes fails | ||||
# (usually due to unicode error message) | ||||
try: | ||||
estr = str(e) | ||||
except Exception: | ||||
estr = "unknown" | ||||
# and class name | ||||
try: | ||||
klass = _safe_getattr(obj, '__class__', None) or type(obj) | ||||
mod = _safe_getattr(klass, '__module__', None) | ||||
if mod in (None, '__builtin__', 'builtins', 'exceptions'): | ||||
classname = klass.__name__ | ||||
else: | ||||
classname = mod + '.' + klass.__name__ | ||||
except Exception: | ||||
# this may be paranoid, but we already know repr is broken | ||||
classname = "unknown type" | ||||
# the informative repr | ||||
return "<repr(<{} at 0x{:x}>) failed: {}: {}>".format( | ||||
classname, id(obj), ename, estr, | ||||
) | ||||
MinRK
|
r13424 | def _safe_repr(obj): | ||
MinRK
|
r13430 | """Don't assume repr is not broken.""" | ||
MinRK
|
r13424 | try: | ||
return repr(obj) | ||||
except Exception as e: | ||||
MinRK
|
r13430 | return _failed_repr(obj, e) | ||
MinRK
|
r13424 | |||
MinRK
|
r13430 | def _safe_getattr(obj, attr, default=None): | ||
MinRK
|
r13434 | """Safe version of getattr. | ||
MinRK
|
r13430 | |||
MinRK
|
r13434 | Same as getattr, but will return ``default`` on any Exception, | ||
rather than raising. | ||||
MinRK
|
r13430 | """ | ||
try: | ||||
MinRK
|
r13434 | return getattr(obj, attr, default) | ||
MinRK
|
r13430 | except Exception: | ||
return default | ||||
Robert Kern
|
r1831 | |||
def pretty(obj, verbose=False, max_width=79, newline='\n'): | ||||
""" | ||||
Pretty print the object's representation. | ||||
""" | ||||
stream = StringIO() | ||||
printer = RepresentationPrinter(stream, verbose, max_width, newline) | ||||
printer.pretty(obj) | ||||
printer.flush() | ||||
return stream.getvalue() | ||||
def pprint(obj, verbose=False, max_width=79, newline='\n'): | ||||
""" | ||||
Like `pretty` but print to stdout. | ||||
""" | ||||
printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline) | ||||
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: | ||||
Walter Doerwald
|
r6294 | yield | ||
Robert Kern
|
r1831 | 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` | ||||
Brian Granger
|
r3879 | this printer knows nothing about the default pprinters or the `_repr_pretty_` | ||
Robert Kern
|
r1831 | callback method. | ||
""" | ||||
MinRK
|
r15851 | def __init__(self, output, max_width=79, newline='\n', max_seq_length=1000): | ||
Robert Kern
|
r1831 | self.output = output | ||
self.max_width = max_width | ||||
self.newline = newline | ||||
MinRK
|
r15851 | self.max_seq_length = max_seq_length | ||
Robert Kern
|
r1831 | 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() | ||||
Alex Rudy
|
r11875 | |||
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 | ||||
Robert Kern
|
r1831 | |||
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 | ||||
MinRK
|
r15852 | |||
def _enumerate(self, seq): | ||||
"""like enumerate, but with an upper limit on the number of items""" | ||||
for idx, x in enumerate(seq): | ||||
MinRK
|
r15853 | if self.max_seq_length and idx >= self.max_seq_length: | ||
MinRK
|
r15852 | self.text(',') | ||
self.breakable() | ||||
self.text('...') | ||||
raise StopIteration | ||||
yield idx, x | ||||
Robert Kern
|
r1831 | 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. | ||||
Robert Kern
|
r1864 | 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] | ||||
Robert Kern
|
r1831 | 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. | ||||
""" | ||||
Robert Kern
|
r3208 | def __init__(self, output, verbose=False, max_width=79, newline='\n', | ||
singleton_pprinters=None, type_pprinters=None, deferred_pprinters=None): | ||||
Robert Kern
|
r1831 | PrettyPrinter.__init__(self, output, max_width, newline) | ||
self.verbose = verbose | ||||
self.stack = [] | ||||
Robert Kern
|
r3208 | 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 | ||||
Robert Kern
|
r1831 | |||
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: | ||||
MinRK
|
r13430 | obj_class = _safe_getattr(obj, '__class__', None) or type(obj) | ||
Brian Granger
|
r3879 | # First try to find registered singleton printers for the type. | ||
Robert Kern
|
r1831 | try: | ||
Robert Kern
|
r3208 | printer = self.singleton_pprinters[obj_id] | ||
Robert Kern
|
r1831 | except (TypeError, KeyError): | ||
pass | ||||
else: | ||||
return printer(obj, self, cycle) | ||||
Walter Doerwald
|
r6313 | # Next walk the mro and check for either: | ||
# 1) a registered printer | ||||
# 2) a _repr_pretty_ method | ||||
Robert Kern
|
r1831 | for cls in _get_mro(obj_class): | ||
Robert Kern
|
r3208 | if cls in self.type_pprinters: | ||
Walter Doerwald
|
r6313 | # printer registered in self.type_pprinters | ||
Robert Kern
|
r3208 | return self.type_pprinters[cls](obj, self, cycle) | ||
Robert Kern
|
r1831 | else: | ||
Walter Doerwald
|
r6313 | # deferred printer | ||
Robert Kern
|
r1831 | printer = self._in_deferred_types(cls) | ||
if printer is not None: | ||||
return printer(obj, self, cycle) | ||||
Walter Doerwald
|
r6313 | else: | ||
# Finally look for special method names. | ||||
# Some objects automatically create any requested | ||||
# attribute. Try to ignore most of them by checking for | ||||
# callability. | ||||
Robert Kern
|
r7831 | if '_repr_pretty_' in cls.__dict__: | ||
meth = cls._repr_pretty_ | ||||
Walter Doerwald
|
r6314 | if callable(meth): | ||
return meth(obj, self, cycle) | ||||
Robert Kern
|
r1831 | 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. | ||||
""" | ||||
MinRK
|
r13430 | mod = _safe_getattr(cls, '__module__', None) | ||
name = _safe_getattr(cls, '__name__', None) | ||||
Robert Kern
|
r1831 | key = (mod, name) | ||
printer = None | ||||
Robert Kern
|
r3208 | if key in self.deferred_pprinters: | ||
Robert Kern
|
r1831 | # Move the printer over to the regular registry. | ||
Robert Kern
|
r3208 | printer = self.deferred_pprinters.pop(key) | ||
self.type_pprinters[cls] = printer | ||||
Robert Kern
|
r1831 | 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 | ||||
Thomas Kluyver
|
r4752 | try: | ||
_baseclass_reprs = (object.__repr__, types.InstanceType.__repr__) | ||||
except AttributeError: # Python 3 | ||||
_baseclass_reprs = (object.__repr__,) | ||||
Robert Kern
|
r1831 | |||
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. | ||||
""" | ||||
MinRK
|
r13430 | klass = _safe_getattr(obj, '__class__', None) or type(obj) | ||
if _safe_getattr(klass, '__repr__', None) not in _baseclass_reprs: | ||||
Alex Rudy
|
r11876 | # A user-provided repr. Find newlines and replace them with p.break_() | ||
MinRK
|
r13424 | output = _safe_repr(obj) | ||
Alex Rudy
|
r11876 | for idx,output_line in enumerate(output.splitlines()): | ||
if idx: | ||||
p.break_() | ||||
p.text(output_line) | ||||
Robert Kern
|
r1831 | 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, '>') | ||||
Robert Kern
|
r3883 | def _seq_pprinter_factory(start, end, basetype): | ||
Robert Kern
|
r1831 | """ | ||
Factory that returns a pprint function useful for sequences. Used by | ||||
Robert Kern
|
r10184 | the default pprint for tuples, dicts, and lists. | ||
Robert Kern
|
r1831 | """ | ||
def inner(obj, p, cycle): | ||||
Robert Kern
|
r3883 | 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)) | ||||
Robert Kern
|
r1831 | if cycle: | ||
return p.text(start + '...' + end) | ||||
step = len(start) | ||||
p.begin_group(step, start) | ||||
MinRK
|
r15852 | for idx, x in p._enumerate(obj): | ||
Robert Kern
|
r1831 | if idx: | ||
p.text(',') | ||||
p.breakable() | ||||
p.pretty(x) | ||||
MinRK
|
r15852 | if len(obj) == 1 and type(obj) is tuple: | ||
Robert Kern
|
r1831 | # Special case for 1-item tuples. | ||
p.text(',') | ||||
p.end_group(step, end) | ||||
return inner | ||||
Robert Kern
|
r10184 | 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) | ||||
Robert Kern
|
r10235 | # Like dictionary keys, we will try to sort the items. | ||
items = list(obj) | ||||
try: | ||||
items.sort() | ||||
except Exception: | ||||
# Sometimes the items don't sort. | ||||
pass | ||||
MinRK
|
r15852 | for idx, x in p._enumerate(items): | ||
Robert Kern
|
r10184 | if idx: | ||
p.text(',') | ||||
p.breakable() | ||||
p.pretty(x) | ||||
p.end_group(step, end) | ||||
return inner | ||||
Robert Kern
|
r3883 | def _dict_pprinter_factory(start, end, basetype=None): | ||
Robert Kern
|
r1831 | """ | ||
Factory that returns a pprint function used by the default pprint of | ||||
dicts and dict proxies. | ||||
""" | ||||
def inner(obj, p, cycle): | ||||
Robert Kern
|
r3883 | 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)) | ||||
Robert Kern
|
r1831 | if cycle: | ||
return p.text('{...}') | ||||
p.begin_group(1, start) | ||||
keys = obj.keys() | ||||
try: | ||||
keys.sort() | ||||
Matthias BUSSONNIER
|
r7787 | except Exception as e: | ||
Robert Kern
|
r1831 | # Sometimes the keys don't sort. | ||
pass | ||||
MinRK
|
r15852 | for idx, key in p._enumerate(keys): | ||
Robert Kern
|
r1831 | if idx: | ||
p.text(',') | ||||
p.breakable() | ||||
p.pretty(key) | ||||
p.text(': ') | ||||
p.pretty(obj[key]) | ||||
p.end_group(1, end) | ||||
return inner | ||||
def _super_pprint(obj, p, cycle): | ||||
"""The pprint for the super type.""" | ||||
p.begin_group(8, '<super: ') | ||||
Thomas Kluyver
|
r14997 | p.pretty(obj.__thisclass__) | ||
Robert Kern
|
r1831 | p.text(',') | ||
p.breakable() | ||||
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.""" | ||||
Thomas Kluyver
|
r16391 | # Heap allocated types might not have the module attribute, | ||
# and others may set it to None. | ||||
MinRK
|
r13430 | mod = _safe_getattr(obj, '__module__', None) | ||
Thomas Kluyver
|
r16391 | name = _safe_getattr(obj, '__qualname__', obj.__name__) | ||
Bradley M. Froehle
|
r8872 | |||
Thomas Kluyver
|
r16391 | if mod in (None, '__builtin__', 'builtins', 'exceptions'): | ||
p.text(name) | ||||
Robert Kern
|
r1831 | else: | ||
Thomas Kluyver
|
r16391 | p.text(mod + '.' + name) | ||
Robert Kern
|
r1831 | |||
def _repr_pprint(obj, p, cycle): | ||||
"""A pprint that just redirects to the normal repr function.""" | ||||
MinRK
|
r13424 | p.text(_safe_repr(obj)) | ||
Robert Kern
|
r1831 | |||
def _function_pprint(obj, p, cycle): | ||||
"""Base pprint for all functions and builtin functions.""" | ||||
Thomas Kluyver
|
r16391 | name = _safe_getattr(obj, '__qualname__', obj.__name__) | ||
mod = obj.__module__ | ||||
if mod and mod not in ('__builtin__', 'builtins', 'exceptions'): | ||||
name = mod + '.' + name | ||||
Robert Kern
|
r1831 | p.text('<function %s>' % name) | ||
def _exception_pprint(obj, p, cycle): | ||||
"""Base pprint for all exceptions.""" | ||||
Thomas Kluyver
|
r16391 | name = getattr(obj.__class__, '__qualname__', obj.__class__.__name__) | ||
if obj.__class__.__module__ not in ('exceptions', 'builtins'): | ||||
name = '%s.%s' % (obj.__class__.__module__, name) | ||||
Robert Kern
|
r1831 | step = len(name) + 1 | ||
Robert Kern
|
r6296 | p.begin_group(step, name + '(') | ||
Robert Kern
|
r1831 | 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, | ||||
Robert Kern
|
r3883 | tuple: _seq_pprinter_factory('(', ')', tuple), | ||
list: _seq_pprinter_factory('[', ']', list), | ||||
dict: _dict_pprinter_factory('{', '}', dict), | ||||
Thomas Kluyver
|
r4752 | |||
Robert Kern
|
r10184 | set: _set_pprinter_factory('{', '}', set), | ||
frozenset: _set_pprinter_factory('frozenset({', '})', frozenset), | ||||
Robert Kern
|
r1831 | super: _super_pprint, | ||
_re_pattern_type: _re_pattern_pprint, | ||||
type: _type_pprint, | ||||
types.FunctionType: _function_pprint, | ||||
types.BuiltinFunctionType: _function_pprint, | ||||
types.MethodType: _repr_pprint, | ||||
Thomas Kluyver
|
r4752 | |||
Robert Kern
|
r1831 | datetime.datetime: _repr_pprint, | ||
datetime.timedelta: _repr_pprint, | ||||
_exception_base: _exception_pprint | ||||
} | ||||
Thomas Kluyver
|
r4752 | try: | ||
_type_pprinters[types.DictProxyType] = _dict_pprinter_factory('<dictproxy {', '}>') | ||||
MinRK
|
r5545 | _type_pprinters[types.ClassType] = _type_pprint | ||
Thomas Kluyver
|
r13358 | _type_pprinters[types.SliceType] = _repr_pprint | ||
except AttributeError: # Python 3 | ||||
_type_pprinters[slice] = _repr_pprint | ||||
Thomas Kluyver
|
r4752 | |||
try: | ||||
_type_pprinters[xrange] = _repr_pprint | ||||
Thomas Kluyver
|
r13358 | _type_pprinters[long] = _repr_pprint | ||
_type_pprinters[unicode] = _repr_pprint | ||||
Thomas Kluyver
|
r4752 | except NameError: | ||
_type_pprinters[range] = _repr_pprint | ||||
Thomas Kluyver
|
r13358 | _type_pprinters[bytes] = _repr_pprint | ||
Thomas Kluyver
|
r4752 | |||
Robert Kern
|
r1831 | #: 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) | ||||
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): | ||||
Thomas Kluyver
|
r13348 | print("foo") | ||
Robert Kern
|
r1831 | |||
pprint(Foo(), verbose=True) | ||||