Spaces:
Runtime error
Runtime error
| """ | |
| 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'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)) | |
| 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:: IPython.lib.pretty | |
| :parts: 3 | |
| :copyright: 2007 by Armin Ronacher. | |
| Portions (c) 2009 by Robert Kern. | |
| :license: BSD License. | |
| """ | |
| from contextlib import contextmanager | |
| import datetime | |
| import os | |
| import re | |
| import sys | |
| import types | |
| from collections import deque | |
| from inspect import signature | |
| from io import StringIO | |
| from warnings import warn | |
| from IPython.utils.decorators import undoc | |
| from IPython.utils.py3compat import PYPY | |
| from typing import Dict | |
| # Allow pretty-printing of functions with PEP-649 annotations | |
| if sys.version_info >= (3, 14): | |
| from annotationlib import Format | |
| from functools import partial | |
| signature = partial(signature, annotation_format=Format.FORWARDREF) | |
| __all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter', | |
| 'for_type', 'for_type_by_name', 'RawText', 'RawStringLiteral', 'CallExpression'] | |
| 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 | |
| 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: | |
| def indent(self, indent): | |
| """with statement support for indenting/dedenting.""" | |
| self.indentation += indent | |
| try: | |
| yield | |
| finally: | |
| self.indentation -= indent | |
| 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_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 | |
| def _break_outer_groups(self): | |
| while self.max_width < self.output_width + self.buffer_width: | |
| group = self.group_queue.deq() | |
| if not group: | |
| return | |
| self._break_one_group(group) | |
| 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. | |
| """ | |
| group = self.group_queue.deq() | |
| if group: | |
| self._break_one_group(group) | |
| 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. | |
| 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) | |
| if ( | |
| cls is not object | |
| # check if cls defines __repr__ | |
| and "__repr__" in cls.__dict__ | |
| # check if __repr__ is callable. | |
| # Note: we need to test getattr(cls, '__repr__') | |
| # instead of cls.__dict__['__repr__'] | |
| # in order to work with descriptors like partialmethod, | |
| and callable(_safe_getattr(cls, "__repr__", None)) | |
| ): | |
| return _repr_pprint(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: | |
| 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: | |
| 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 | |
| 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 managing | |
| # will kick in. | |
| self = __self | |
| self.name = __name | |
| self.args = args | |
| self.kwargs = kwargs | |
| 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 managing | |
| # 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) | |
| 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): | |
| """ | |
| Factory that returns a pprint function useful for sequences. Used by | |
| the default pprint for tuples and lists. | |
| """ | |
| def inner(obj, p, cycle): | |
| 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 isinstance(obj, tuple): | |
| # Special case for 1-item tuples. | |
| p.text(',') | |
| p.end_group(step, end) | |
| return inner | |
| def _set_pprinter_factory(start, end): | |
| """ | |
| 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. | |
| p.text(type(obj).__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): | |
| """ | |
| 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('{...}') | |
| step = len(start) | |
| p.begin_group(step, start) | |
| keys = obj.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, '>') | |
| class _ReFlags: | |
| def __init__(self, value): | |
| self.value = value | |
| def _repr_pretty_(self, p, cycle): | |
| done_one = False | |
| for flag in ( | |
| "IGNORECASE", | |
| "LOCALE", | |
| "MULTILINE", | |
| "DOTALL", | |
| "UNICODE", | |
| "VERBOSE", | |
| "DEBUG", | |
| ): | |
| if self.value & getattr(re, flag): | |
| if done_one: | |
| p.text('|') | |
| p.text('re.' + flag) | |
| done_one = True | |
| 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))) | |
| def _types_simplenamespace_pprint(obj, p, cycle): | |
| """The pprint function for types.SimpleNamespace.""" | |
| namespace = CallExpression.factory('namespace') | |
| if cycle: | |
| p.pretty(namespace(RawText("..."))) | |
| else: | |
| p.pretty(namespace(**obj.__dict__)) | |
| 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) | |
| lines = output.splitlines() | |
| with p.group(): | |
| for idx, output_line in enumerate(lines): | |
| 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) | |
| p.pretty(CallExpression(name, *getattr(obj, 'args', ()))) | |
| #: the exception base | |
| _exception_base: type | |
| 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('(', ')'), | |
| list: _seq_pprinter_factory('[', ']'), | |
| dict: _dict_pprinter_factory('{', '}'), | |
| set: _set_pprinter_factory('{', '}'), | |
| frozenset: _set_pprinter_factory('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, | |
| types.SimpleNamespace: _types_simplenamespace_pprint, | |
| datetime.datetime: _repr_pprint, | |
| datetime.timedelta: _repr_pprint, | |
| _exception_base: _exception_pprint | |
| } | |
| # 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{', '}') | |
| _type_pprinters[types.MappingProxyType] = _dict_pprinter_factory("mappingproxy({", "})") | |
| _type_pprinters[slice] = _repr_pprint | |
| _type_pprinters[range] = _repr_pprint | |
| _type_pprinters[bytes] = _repr_pprint | |
| #: printers for types specified by name | |
| _deferred_type_pprinters: Dict = {} | |
| 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): | |
| cls_ctor = CallExpression.factory(obj.__class__.__name__) | |
| if cycle: | |
| p.pretty(cls_ctor(RawText("..."))) | |
| else: | |
| p.pretty(cls_ctor(obj.default_factory, dict(obj))) | |
| def _ordereddict_pprint(obj, p, cycle): | |
| 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()) | |
| def _deque_pprint(obj, p, cycle): | |
| cls_ctor = CallExpression.factory(obj.__class__.__name__) | |
| if cycle: | |
| p.pretty(cls_ctor(RawText("..."))) | |
| elif obj.maxlen is not None: | |
| p.pretty(cls_ctor(list(obj), maxlen=obj.maxlen)) | |
| else: | |
| p.pretty(cls_ctor(list(obj))) | |
| def _counter_pprint(obj, p, cycle): | |
| cls_ctor = CallExpression.factory(obj.__class__.__name__) | |
| if cycle: | |
| p.pretty(cls_ctor(RawText("..."))) | |
| elif len(obj): | |
| p.pretty(cls_ctor(dict(obj.most_common()))) | |
| else: | |
| p.pretty(cls_ctor()) | |
| def _userlist_pprint(obj, p, cycle): | |
| cls_ctor = CallExpression.factory(obj.__class__.__name__) | |
| if cycle: | |
| p.pretty(cls_ctor(RawText("..."))) | |
| else: | |
| p.pretty(cls_ctor(obj.data)) | |
| 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) | |
| for_type_by_name("collections", "UserList", _userlist_pprint) | |
| if __name__ == '__main__': | |
| from random import randrange | |
| class Foo: | |
| 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) | |