Here's a text-based object browser that is helpful when working with big complicated data structures.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | class ObjectDescender:
def __init__(self, maxdepth, outf=sys.stderr):
self.already = [ ]
self.maxdepth = maxdepth
self.outf = outf
def exclude(self, attr, obj):
return False
def showThis(self, attr, obj):
return True
def prefix(self, depth, pn):
return ((depth * "\t") + ".".join(pn) + ": ")
def handleLeaf(self, v, depth, pn):
def trepr(v):
if v == None:
return "None"
elif type(v) == types.InstanceType:
r = v.__class__.__name__
else:
r = repr(type(v))
return "%s at %x" % (r, id(v))
if type(v) in (types.ListType, types.TupleType):
self.outf.write(self.prefix(depth, pn) + trepr(v))
if len(v) == 0:
self.outf.write(" (empty)")
self.outf.write("\n")
elif type(v) in (types.StringType, types.IntType,
types.FloatType, types.ComplexType):
self.outf.write(self.prefix(depth, pn) + repr(v) + "\n")
else:
self.outf.write(self.prefix(depth, pn) + trepr(v) + "\n")
def getAttributes(self, obj):
lst = dir(obj)
if hasattr(obj, "__dict__"):
for x in obj.__dict__.keys():
if x not in lst:
lst.append(x)
lst.sort()
def filt(x):
return x not in ("__doc__",)
return filter(filt, lst)
def descend(self, obj, depth=0, pathname=[ ]):
if obj in self.already:
return
self.already.append(obj)
if depth == 0:
self.handleLeaf(obj, depth, pathname)
if depth >= self.maxdepth:
return
if type(obj) in (types.ListType, types.TupleType):
lst = [ ]
if len(pathname) > 0:
lastitem = pathname[-1]
pathname = pathname[:-1]
else:
lastitem = ""
for i in range(len(obj)):
x = obj[i]
if not self.exclude(i, x):
y = pathname + [ lastitem + ("[%d]" % i) ]
lst.append((i, x, y))
for i, v, pn in lst:
if self.showThis(i, v):
self.handleLeaf(v, depth+1, pn)
for i, v, pn in lst:
self.descend(v, depth+1, pn)
elif type(obj) in (types.DictType,):
keys = obj.keys()
lst = [ ]
if len(pathname) > 0:
lastitem = pathname[-1]
pathname = pathname[:-1]
else:
lastitem = ""
for k in keys:
x = obj[k]
if not self.exclude(k, x):
y = pathname + [ lastitem + ("[%s]" % repr(k)) ]
lst.append((k, x, y))
for k, v, pn in lst:
if self.showThis(k, v):
self.handleLeaf(v, depth+1, pn)
for k, v, pn in lst:
self.descend(v, depth+1, pn)
elif (hasattr(obj, "__class__") or
type(obj) in (types.InstanceType, types.ClassType,
types.ModuleType, types.FunctionType)):
ckeys = [ ]
if True:
# Look at instance variables, ignore class variables and methods
if hasattr(obj, "__class__"):
ckeys = self.getAttributes(obj.__class__)
else:
# Look at all variables and methods
ckeys = ( )
keys = filter(lambda x: x not in ckeys, self.getAttributes(obj))
lst = [ ]
for k in keys:
x = getattr(obj, k)
if not self.exclude(k, x):
lst.append((k, x, pathname + [ k ]))
for k, v, pn in lst:
if self.showThis(k, v):
self.handleLeaf(v, depth+1, pn)
for k, v, pn in lst:
self.descend(v, depth+1, pn)
def standardExclude(attr, obj):
# This is specific to the codebase I am currently working in.
# These classes have a lot of internals that are rarely of interest.
from MWsemantics import MWsemantics
from GLPane import GLPane
return isinstance(obj, MWsemantics) or isinstance(obj, GLPane)
def objectBrowse(obj, maxdepth=5, exclude=standardExclude, showThis=None, outf=sys.stderr):
od = ObjectDescender(maxdepth=maxdepth, outf=outf)
if showThis != None:
od.showThis = showThis
od.exclude = exclude
od.descend(obj, pathname=['arg'])
def findChild(obj, showThis, maxdepth=8):
# Drill down deeper because we're being more selective
def prefix(depth, pn):
# no indentation
return (".".join(pn) + ": ")
f = Finder(maxdepth=maxdepth)
f.showThis = showThis
f.prefix = prefix
f.descend(obj, pathname=['arg'])
|
The ObjectDescender class can also be customized for related uses, e.g. searching for a child of the object that meets some criterion. Any child object that has already been found is only explored once.
Tags: debugging