--- /dev/null
+#!/usr/bin/python
+# Released into the public domain.
+# Written by Mike Frysinger <vapier>.
+
+"""Module for diving into python objects."""
+
+from __future__ import print_function
+
+
+class Dump(object):
+
+ import cStringIO
+ import datetime
+ import logging
+ import pydoc
+ import os
+ import sys
+ import types
+
+ MAX_DEPTH = 1
+
+ # Objects that hold multiple objects (can be looped over).
+ TYPES_ITERABLES = (
+ types.GeneratorType,
+ types.ListType,
+ types.TupleType,
+ )
+
+ # Objects that we shouldn't really probe.
+ TYPES_CALLABLE = (
+ types.FunctionType,
+ types.LambdaType,
+ )
+
+ # Simple objects we don't decode further.
+ TYPES_SCALAR = (
+ types.BooleanType,
+ types.ComplexType,
+ types.FloatType,
+ types.IntType,
+ types.LongType,
+ types.NoneType,
+ types.StringType,
+ types.UnicodeType,
+
+ types.ClassType,
+ types.TypeType,
+ )
+
+ # Objects that are dictionary based.
+ TYPES_DICT = (
+ types.DictType,
+ types.DictionaryType,
+ )
+
+ # Standard python objects we don't normally expand.
+ TYPES_STANDARD = (
+ datetime.date,
+ datetime.datetime,
+ datetime.time,
+ logging.Logger
+ )
+
+ # Color logic.
+ _C = lambda x: '\033[%im' % x
+ def C(self, m, c):
+ return '%s%s%s' % (c, m, self.NORMAL)
+ NORMAL = _C(0)
+ BOLD = _C(1)
+ UNDERLINE = _C(4)
+ #BLACK = _C()
+
+ PURPLE = _C(95)
+ CYAN = _C(96)
+ DARKCYAN = _C(36)
+ BLUE = _C(94)
+ GREEN = _C(92)
+ YELLOW = _C(93)
+ RED = _C(91)
+
+ def __init__(self, obj, depth=None, out=None, linelim=150,
+ show_internal=False, show_all=False, show_std=False):
+ if out is None:
+ out = self.cStringIO.StringIO()
+ #out = self.sys.stdout
+ self.out = out
+
+ self.depth = depth if depth else self.MAX_DEPTH
+ self.line_limit = linelim
+ self.show_internal = show_internal
+ self.show_all = show_all
+ self.show_std = show_std
+
+ self.seen = set()
+ self.dump(obj)
+
+ if hasattr(out, 'getvalue'):
+ self.pydoc.pager(out.getvalue())
+
+ return None
+
+ def trunc(self, s):
+ """Truncate |s| length to self.line_limit bytes"""
+ if len(s) > self.line_limit:
+ s = '%s %s' % (s[0:self.line_limit],
+ self.C('<truncated>', self.RED))
+ return s
+
+ def dump(self, obj, depth=0, name=None):
+ """Dump |obj| with |name|"""
+ indent = ' ' * depth
+ def w(msg, indent=indent, color=None):
+ for line in msg.splitlines():
+ if color:
+ line = self.C(line, color)
+ self.out.write('%s%s\n' % (indent, line))
+ def d(obj, **kwargs):
+ try:
+ self.dump(obj, depth=depth + 1, **kwargs)
+ except Exception as e:
+ w(' <error probing>: %s' % (e,), color=self.RED)
+ raise
+
+ if ((not self.show_std and isinstance(obj, self.TYPES_STANDARD)) or
+ isinstance(obj, self.TYPES_SCALAR)):
+ w('%s: %s' % (self.C(name, self.BOLD), obj), indent=indent[:-2])
+ return
+
+ try:
+ if obj in self.seen:
+ w('%s: %s' % (self.C(name, self.BOLD),
+ self.C('<loop>', self.RED)), indent=indent[:-2])
+ return
+ self.seen.add(obj)
+ except TypeError:
+ pass
+
+ if name:
+ w('%s' % (name,), color=self.BOLD, indent=indent[:-2])
+
+ objr = repr(obj)
+ objs = str(obj)
+ if objr == objs:
+ w('%s: %s' % (type(obj), self.trunc(objs),))
+ else:
+ w('Object.type: %s' % (type(obj),))
+ w(' .repr: %s' % (self.trunc(objr),))
+ w(' .str : %s' % (self.trunc(objs),))
+
+ if depth > self.depth:
+ w('<stop; depth limit hit at %i>' % (depth,), color=self.RED)
+ return
+
+ if isinstance(obj, self.TYPES_ITERABLES):
+ # Iterable types.
+ for i, o in enumerate(obj):
+ d(o, name='[%i]' % (i,))
+ elif isinstance(obj, self.TYPES_SCALAR):
+ # Scalar types; already shown above.
+ pass
+ elif isinstance(obj, self.TYPES_DICT):
+ # Dictionary types.
+ for k, v in obj.items():
+ d(v, name='{%r}' % (k,))
+ elif isinstance(obj, self.TYPES_STANDARD):
+ # Standard types; already shown above.
+ pass
+ elif isinstance(obj, self.TYPES_CALLABLE):
+ # Callable functions.
+ doc = getattr(obj, 'func_doc', None)
+ if doc:
+ w('"""%s"""' % (doc.strip(),), indent=indent + ' ',
+ color=self.BLUE)
+ else:
+ # Unknown type; probe it!
+ doc = getattr(obj, '__doc__', None)
+ if doc:
+ w('"""%s"""' % (doc.strip(),), indent=indent + ' ',
+ color=self.BLUE)
+
+ for k, v in getattr(obj, '__dict__', {}).items():
+ d(v, name='{%r}' % (k,))
+
+ for k in dir(obj):
+ try:
+ s = self.trunc(repr(getattr(obj, k)))
+ except Exception as e:
+ w(' %s: %s' % (self.C(k, self.BOLD),
+ self.C('<error> %s' % str(e), self.RED)))
+ continue
+
+ if k.startswith('__'):
+ if self.show_all or not k.endswith('__'):
+ w(' %s (skipping): %s' % (self.C(k, self.BOLD), s))
+ elif self.show_internal or not k.startswith('_'):
+ d(getattr(obj, k), name=k)
+
+
+def dump(*args, **kwargs):
+ d = Dump(*args, **kwargs)
+ del d