pretty.py
941 lines
| 29.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 | |||
Eric Wieser
|
r25641 | Here's an example for a class with a simple constructor:: | ||
class MySimpleObject: | ||||
def __init__(self, a, b, *, c=None): | ||||
self.a = a | ||||
self.b = b | ||||
self.c = c | ||||
def _repr_pretty_(self, p, cycle): | ||||
ctor = CallExpression.factory(self.__class__.__name__) | ||||
if self.c is None: | ||||
p.pretty(ctor(a, b)) | ||||
else: | ||||
p.pretty(ctor(a, b, c=c)) | ||||
Frazer McLean
|
r21376 | Here is an example implementation of a `_repr_pretty_` method for a list | ||
subclass:: | ||||
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 | ||
Frazer McLean
|
r21376 | 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`. | ||||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | If you just want to indent something you can use the group function | ||
Frazer McLean
|
r21536 | without open / close parameters. You can also use this code:: | ||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | with p.indent(2): | ||
... | ||||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r8795 | 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 | """ | ||
Min RK
|
r24372 | |||
Thomas Kluyver
|
r3115 | from contextlib import contextmanager | ||
Min RK
|
r24372 | import datetime | ||
import os | ||||
import re | ||||
Robert Kern
|
r1831 | import sys | ||
import types | ||||
from collections import deque | ||||
Alyssa Whitwell
|
r24454 | from inspect import signature | ||
Srinivas Reddy Thatiparthy
|
r23120 | from io import StringIO | ||
Thomas Kluyver
|
r23130 | from warnings import warn | ||
Robert Kern
|
r1831 | |||
Thomas Kluyver
|
r23165 | from IPython.utils.decorators import undoc | ||
Srinivas Reddy Thatiparthy
|
r23699 | from IPython.utils.py3compat import PYPY | ||
Robert Kern
|
r1831 | |||
__all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter', | ||||
Eric Wieser
|
r25641 | 'for_type', 'for_type_by_name', 'RawText', 'RawStringLiteral', 'CallExpression'] | ||
Robert Kern
|
r1831 | |||
MinRK
|
r15852 | |||
Min RK
|
r18518 | MAX_SEQ_LENGTH = 1000 | ||
Robert Kern
|
r1831 | _re_pattern_type = type(re.compile('')) | ||
MinRK
|
r13430 | def _safe_getattr(obj, attr, default=None): | ||
MinRK
|
r13434 | """Safe version of getattr. | ||
luz.paz
|
r24494 | |||
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 | |||
Thomas Kluyver
|
r23165 | @undoc | ||
Thomas Kluyver
|
r23130 | class CUnicodeIO(StringIO): | ||
def __init__(self, *args, **kwargs): | ||||
super().__init__(*args, **kwargs) | ||||
warn(("CUnicodeIO is deprecated since IPython 6.0. " | ||||
"Please use io.StringIO instead."), | ||||
DeprecationWarning, stacklevel=2) | ||||
Min RK
|
r20486 | |||
Jeroen Demeyer
|
r23872 | 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 | ||||
Min RK
|
r18518 | def pretty(obj, verbose=False, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH): | ||
Robert Kern
|
r1831 | """ | ||
Pretty print the object's representation. | ||||
""" | ||||
Srinivas Reddy Thatiparthy
|
r23120 | stream = StringIO() | ||
Jacob Niehus
|
r21903 | printer = RepresentationPrinter(stream, verbose, max_width, newline, max_seq_length=max_seq_length) | ||
Robert Kern
|
r1831 | printer.pretty(obj) | ||
printer.flush() | ||||
return stream.getvalue() | ||||
Min RK
|
r18518 | def pprint(obj, verbose=False, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH): | ||
Robert Kern
|
r1831 | """ | ||
Like `pretty` but print to stdout. | ||||
""" | ||||
Jacob Niehus
|
r21903 | printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline, max_seq_length=max_seq_length) | ||
Robert Kern
|
r1831 | 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. | ||
""" | ||||
Min RK
|
r18518 | def __init__(self, output, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH): | ||
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 | ||||
Eric Wieser
|
r25435 | def _break_one_group(self, group): | ||
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 | ||||
Eric Wieser
|
r25440 | def _break_outer_groups(self): | ||
Robert Kern
|
r1831 | while self.max_width < self.output_width + self.buffer_width: | ||
group = self.group_queue.deq() | ||||
if not group: | ||||
return | ||||
Eric Wieser
|
r25435 | self._break_one_group(group) | ||
Robert Kern
|
r1831 | |||
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() | ||||
luz.paz
|
r24494 | |||
Alex Rudy
|
r11875 | def break_(self): | ||
""" | ||||
Explicitly insert a newline into the output, maintaining correct indentation. | ||||
""" | ||||
Eric Wieser
|
r25435 | group = self.group_queue.deq() | ||
if group: | ||||
self._break_one_group(group) | ||||
Alex Rudy
|
r11875 | self.flush() | ||
self.output.write(self.newline) | ||||
self.output.write(' ' * self.indentation) | ||||
self.output_width = self.indentation | ||||
self.buffer_width = 0 | ||||
luz.paz
|
r24494 | |||
Robert Kern
|
r1831 | |||
def begin_group(self, indent=0, open=''): | ||||
""" | ||||
Terry Davis
|
r25450 | Begin a group. | ||
Robert Kern
|
r1831 | 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 | ||||
luz.paz
|
r24494 | |||
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('...') | ||||
Matthias Bussonnier
|
r21959 | return | ||
MinRK
|
r15852 | yield idx, x | ||
luz.paz
|
r24494 | |||
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', | ||
Min RK
|
r18518 | singleton_pprinters=None, type_pprinters=None, deferred_pprinters=None, | ||
max_seq_length=MAX_SEQ_LENGTH): | ||||
Robert Kern
|
r3208 | |||
Min RK
|
r18518 | PrettyPrinter.__init__(self, output, max_width, newline, max_seq_length=max_seq_length) | ||
Robert Kern
|
r1831 | 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) | ||||
Thomas Kluyver
|
r24108 | if cls is not object \ | ||
and callable(cls.__dict__.get('__repr__')): | ||||
return _repr_pprint(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 | ||||
Eric Wieser
|
r25641 | class RawText: | ||
""" Object such that ``p.pretty(RawText(value))`` is the same as ``p.text(value)``. | ||||
An example usage of this would be to show a list as binary numbers, using | ||||
``p.pretty([RawText(bin(i)) for i in integers])``. | ||||
""" | ||||
def __init__(self, value): | ||||
self.value = value | ||||
def _repr_pretty_(self, p, cycle): | ||||
p.text(self.value) | ||||
class CallExpression: | ||||
""" Object which emits a line-wrapped call expression in the form `__name(*args, **kwargs)` """ | ||||
def __init__(__self, __name, *args, **kwargs): | ||||
# dunders are to avoid clashes with kwargs, as python's name manging | ||||
# will kick in. | ||||
self = __self | ||||
self.name = __name | ||||
self.args = args | ||||
self.kwargs = kwargs | ||||
@classmethod | ||||
def factory(cls, name): | ||||
def inner(*args, **kwargs): | ||||
return cls(name, *args, **kwargs) | ||||
return inner | ||||
def _repr_pretty_(self, p, cycle): | ||||
# dunders are to avoid clashes with kwargs, as python's name manging | ||||
# will kick in. | ||||
started = False | ||||
def new_item(): | ||||
nonlocal started | ||||
if started: | ||||
p.text(",") | ||||
p.breakable() | ||||
started = True | ||||
prefix = self.name + "(" | ||||
with p.group(len(prefix), prefix, ")"): | ||||
for arg in self.args: | ||||
new_item() | ||||
p.pretty(arg) | ||||
for arg_name, arg in self.kwargs.items(): | ||||
new_item() | ||||
arg_prefix = arg_name + "=" | ||||
with p.group(len(arg_prefix), arg_prefix): | ||||
p.pretty(arg) | ||||
class RawStringLiteral: | ||||
""" Wrapper that shows a string with a `r` prefix """ | ||||
def __init__(self, value): | ||||
self.value = value | ||||
def _repr_pretty_(self, p, cycle): | ||||
base_repr = repr(self.value) | ||||
if base_repr[:1] in 'uU': | ||||
base_repr = base_repr[1:] | ||||
prefix = 'ur' | ||||
else: | ||||
prefix = 'r' | ||||
base_repr = prefix + base_repr.replace('\\\\', '\\') | ||||
p.text(base_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) | ||
Matthias Bussonnier
|
r23687 | if _safe_getattr(klass, '__repr__', None) is not object.__repr__: | ||
Alex Rudy
|
r11876 | # A user-provided repr. Find newlines and replace them with p.break_() | ||
Remi Rampin
|
r18371 | _repr_pprint(obj, p, cycle) | ||
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, '>') | ||||
Thomas Kluyver
|
r24109 | def _seq_pprinter_factory(start, end): | ||
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): | ||||
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) | ||||
Eric Wieser
|
r25652 | if len(obj) == 1 and isinstance(obj, tuple): | ||
Robert Kern
|
r1831 | # Special case for 1-item tuples. | ||
p.text(',') | ||||
p.end_group(step, end) | ||||
return inner | ||||
Thomas Kluyver
|
r24109 | def _set_pprinter_factory(start, end): | ||
Robert Kern
|
r10184 | """ | ||
Factory that returns a pprint function useful for sets and frozensets. | ||||
""" | ||||
def inner(obj, p, cycle): | ||||
if cycle: | ||||
return p.text(start + '...' + end) | ||||
if len(obj) == 0: | ||||
# Special case. | ||||
Thomas Kluyver
|
r24109 | p.text(type(obj).__name__ + '()') | ||
Robert Kern
|
r10184 | else: | ||
step = len(start) | ||||
p.begin_group(step, start) | ||||
MinRK
|
r18457 | # 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): | ||||
Jeroen Demeyer
|
r23872 | items = _sorted_for_pprint(obj) | ||
else: | ||||
items = obj | ||||
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 | ||||
Thomas Kluyver
|
r24109 | def _dict_pprinter_factory(start, end): | ||
Robert Kern
|
r1831 | """ | ||
Factory that returns a pprint function used by the default pprint of | ||||
dicts and dict proxies. | ||||
""" | ||||
def inner(obj, p, cycle): | ||||
if cycle: | ||||
return p.text('{...}') | ||||
Danilo J. S. Bellini
|
r22748 | step = len(start) | ||
p.begin_group(step, start) | ||||
Robert Kern
|
r1831 | keys = obj.keys() | ||
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]) | ||||
Danilo J. S. Bellini
|
r22748 | p.end_group(step, end) | ||
Robert Kern
|
r1831 | 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() | ||||
Danilo J. S. Bellini
|
r22756 | if PYPY: # In PyPy, super() objects don't have __self__ attributes | ||
Danilo J. S. Bellini
|
r22751 | dself = obj.__repr__.__self__ | ||
p.pretty(None if dself is obj else dself) | ||||
else: | ||||
p.pretty(obj.__self__) | ||||
Robert Kern
|
r1831 | p.end_group(8, '>') | ||
Eric Wieser
|
r25641 | |||
class _ReFlags: | ||||
def __init__(self, value): | ||||
self.value = value | ||||
def _repr_pretty_(self, p, cycle): | ||||
Robert Kern
|
r1831 | done_one = False | ||
for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL', | ||||
'UNICODE', 'VERBOSE', 'DEBUG'): | ||||
Eric Wieser
|
r25641 | if self.value & getattr(re, flag): | ||
Robert Kern
|
r1831 | if done_one: | ||
p.text('|') | ||||
p.text('re.' + flag) | ||||
done_one = True | ||||
Eric Wieser
|
r25641 | |||
def _re_pattern_pprint(obj, p, cycle): | ||||
"""The pprint function for regular expression patterns.""" | ||||
re_compile = CallExpression.factory('re.compile') | ||||
if obj.flags: | ||||
p.pretty(re_compile(RawStringLiteral(obj.pattern), _ReFlags(obj.flags))) | ||||
else: | ||||
p.pretty(re_compile(RawStringLiteral(obj.pattern))) | ||||
Robert Kern
|
r1831 | |||
Eric Wieser
|
r25623 | def _types_simplenamespace_pprint(obj, p, cycle): | ||
"""The pprint function for types.SimpleNamespace.""" | ||||
Eric Wieser
|
r25641 | namespace = CallExpression.factory('namespace') | ||
if cycle: | ||||
p.pretty(namespace(RawText("..."))) | ||||
else: | ||||
p.pretty(namespace(**obj.__dict__)) | ||||
Eric Wieser
|
r25623 | |||
Robert Kern
|
r1831 | def _type_pprint(obj, p, cycle): | ||
"""The pprint for classes and types.""" | ||||
Thomas Kluyver
|
r16239 | # Heap allocated types might not have the module attribute, | ||
# and others may set it to None. | ||||
Remi Rampin
|
r18370 | |||
Danilo J. S. Bellini
|
r22752 | # 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]: | ||||
Remi Rampin
|
r18371 | _repr_pprint(obj, p, cycle) | ||
Remi Rampin
|
r18370 | return | ||
MinRK
|
r13430 | mod = _safe_getattr(obj, '__module__', None) | ||
Scott Sanderson
|
r21803 | try: | ||
name = obj.__qualname__ | ||||
Srinivas Reddy Thatiparthy
|
r23037 | if not isinstance(name, str): | ||
Scott Sanderson
|
r21803 | # 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__ | ||||
Srinivas Reddy Thatiparthy
|
r23037 | if not isinstance(name, str): | ||
Scott Sanderson
|
r21803 | name = '<unknown type>' | ||
Bradley M. Froehle
|
r8872 | |||
Thomas Kluyver
|
r16239 | if mod in (None, '__builtin__', 'builtins', 'exceptions'): | ||
p.text(name) | ||||
Robert Kern
|
r1831 | else: | ||
Thomas Kluyver
|
r16239 | p.text(mod + '.' + name) | ||
Robert Kern
|
r1831 | |||
def _repr_pprint(obj, p, cycle): | ||||
"""A pprint that just redirects to the normal repr function.""" | ||||
Remi Rampin
|
r18371 | # Find newlines and replace them with p.break_() | ||
output = repr(obj) | ||||
Eric Wieser
|
r25433 | lines = output.splitlines() | ||
Eric Wieser
|
r25435 | with p.group(): | ||
for idx, output_line in enumerate(lines): | ||||
if idx: | ||||
p.break_() | ||||
p.text(output_line) | ||||
Robert Kern
|
r1831 | |||
def _function_pprint(obj, p, cycle): | ||||
"""Base pprint for all functions and builtin functions.""" | ||||
Thomas Kluyver
|
r16239 | name = _safe_getattr(obj, '__qualname__', obj.__name__) | ||
mod = obj.__module__ | ||||
if mod and mod not in ('__builtin__', 'builtins', 'exceptions'): | ||||
name = mod + '.' + name | ||||
madhu94
|
r24026 | try: | ||
func_def = name + str(signature(obj)) | ||||
except ValueError: | ||||
func_def = name | ||||
p.text('<function %s>' % func_def) | ||||
Robert Kern
|
r1831 | |||
def _exception_pprint(obj, p, cycle): | ||||
"""Base pprint for all exceptions.""" | ||||
Thomas Kluyver
|
r16239 | name = getattr(obj.__class__, '__qualname__', obj.__class__.__name__) | ||
if obj.__class__.__module__ not in ('exceptions', 'builtins'): | ||||
name = '%s.%s' % (obj.__class__.__module__, name) | ||||
Eric Wieser
|
r25641 | |||
p.pretty(CallExpression(name, *getattr(obj, 'args', ()))) | ||||
Robert Kern
|
r1831 | |||
#: 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, | ||||
Thomas Kluyver
|
r24109 | tuple: _seq_pprinter_factory('(', ')'), | ||
list: _seq_pprinter_factory('[', ']'), | ||||
dict: _dict_pprinter_factory('{', '}'), | ||||
set: _set_pprinter_factory('{', '}'), | ||||
frozenset: _set_pprinter_factory('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, | ||||
Eric Wieser
|
r25623 | types.SimpleNamespace: _types_simplenamespace_pprint, | ||
Robert Kern
|
r1831 | datetime.datetime: _repr_pprint, | ||
datetime.timedelta: _repr_pprint, | ||||
_exception_base: _exception_pprint | ||||
} | ||||
Min RK
|
r24372 | # render os.environ like a dict | ||
_env_type = type(os.environ) | ||||
# future-proof in case os.environ becomes a plain dict? | ||||
if _env_type is not dict: | ||||
_type_pprinters[_env_type] = _dict_pprinter_factory('environ{', '}') | ||||
Thomas Kluyver
|
r4752 | try: | ||
Danilo J. S. Bellini
|
r22747 | # In PyPy, types.DictProxyType is dict, setting the dictproxy printer | ||
luz.paz
|
r24493 | # using dict.setdefault avoids overwriting the dict printer | ||
Danilo J. S. Bellini
|
r22747 | _type_pprinters.setdefault(types.DictProxyType, | ||
Danilo J. S. Bellini
|
r22749 | _dict_pprinter_factory('dict_proxy({', '})')) | ||
MinRK
|
r5545 | _type_pprinters[types.ClassType] = _type_pprint | ||
Thomas Kluyver
|
r13358 | _type_pprinters[types.SliceType] = _repr_pprint | ||
except AttributeError: # Python 3 | ||||
Danilo J. S. Bellini
|
r22748 | _type_pprinters[types.MappingProxyType] = \ | ||
_dict_pprinter_factory('mappingproxy({', '})') | ||||
Thomas Kluyver
|
r13358 | _type_pprinters[slice] = _repr_pprint | ||
Min RK
|
r24372 | |||
Terry Davis
|
r25451 | _type_pprinters[range] = _repr_pprint | ||
_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) | ||||
Frazer McLean
|
r21375 | def _defaultdict_pprint(obj, p, cycle): | ||
Eric Wieser
|
r25641 | cls_ctor = CallExpression.factory(obj.__class__.__name__) | ||
if cycle: | ||||
p.pretty(cls_ctor(RawText("..."))) | ||||
else: | ||||
p.pretty(cls_ctor(obj.default_factory, dict(obj))) | ||||
Frazer McLean
|
r21375 | |||
def _ordereddict_pprint(obj, p, cycle): | ||||
Eric Wieser
|
r25641 | cls_ctor = CallExpression.factory(obj.__class__.__name__) | ||
if cycle: | ||||
p.pretty(cls_ctor(RawText("..."))) | ||||
elif len(obj): | ||||
p.pretty(cls_ctor(list(obj.items()))) | ||||
else: | ||||
p.pretty(cls_ctor()) | ||||
Frazer McLean
|
r21375 | |||
def _deque_pprint(obj, p, cycle): | ||||
Eric Wieser
|
r25641 | cls_ctor = CallExpression.factory(obj.__class__.__name__) | ||
if cycle: | ||||
p.pretty(cls_ctor(RawText("..."))) | ||||
else: | ||||
p.pretty(cls_ctor(list(obj))) | ||||
Frazer McLean
|
r21375 | |||
def _counter_pprint(obj, p, cycle): | ||||
Eric Wieser
|
r25641 | cls_ctor = CallExpression.factory(obj.__class__.__name__) | ||
if cycle: | ||||
p.pretty(cls_ctor(RawText("..."))) | ||||
elif len(obj): | ||||
p.pretty(cls_ctor(dict(obj))) | ||||
else: | ||||
p.pretty(cls_ctor()) | ||||
Frazer McLean
|
r21375 | |||
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) | ||||
Robert Kern
|
r1831 | 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) | ||||