]> git.wh0rd.org - home.git/commitdiff
ipython: add a dumper helper
authorMike Frysinger <vapier@gentoo.org>
Sat, 4 Apr 2015 19:14:35 +0000 (15:14 -0400)
committerMike Frysinger <vapier@gentoo.org>
Sat, 4 Apr 2015 19:14:35 +0000 (15:14 -0400)
.ipython/profile_default/startup/50-dump.py [new file with mode: 0644]

diff --git a/.ipython/profile_default/startup/50-dump.py b/.ipython/profile_default/startup/50-dump.py
new file mode 100644 (file)
index 0000000..565c544
--- /dev/null
@@ -0,0 +1,201 @@
+#!/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