Browse Source

working depth-first object discovery

Darren Ranalli 19 years ago
parent
commit
caa7b9404d
1 changed files with 94 additions and 0 deletions
  1. 94 0
      direct/src/showbase/ContainerReport.py

+ 94 - 0
direct/src/showbase/ContainerReport.py

@@ -0,0 +1,94 @@
+from direct.showbase.PythonUtil import Stack, fastRepr, invertDictLossless
+from direct.showbase.PythonUtil import itype, safeRepr
+import types
+
+class ContainerReport:
+    def __init__(self, rootObj, rootObjName=None):
+        self._rootObj = rootObj
+        if rootObjName is None:
+            rootObjName = repr(rootObj)
+        self._visitedIds = set()
+        self._id2pathStr = {}
+        self._id2container = {}
+        self._id2len = {}
+        self._stack = Stack()
+        self._stack.push(rootObj)
+        self._id2pathStr[id(rootObj)] = rootObjName
+        self._traverse()
+    def _examine(self, obj):
+        # return False if it's an object that can't contain or lead to other objects
+        if type(obj) in (types.BooleanType, types.BuiltinFunctionType,
+                         types.BuiltinMethodType, types.ComplexType,
+                         types.FloatType, types.IntType, types.LongType,
+                         types.NoneType, types.NotImplementedType,
+                         types.TypeType, types.CodeType):
+            return False
+        try:
+            length = len(obj)
+        except:
+            length = None
+        if length is not None and length > 0:
+            objId = id(obj)
+            self._id2container[objId] = obj
+            self._id2len[objId] = length
+        return True
+    def _traverse(self):
+        while len(self._stack) > 0:
+            obj = self._stack.pop()
+            #print '_traverse: %s' % fastRepr(obj, 30)
+            try:
+                dirList = dir(obj)
+            except:
+                pass
+            else:
+                for name in dirList:
+                    if name[-2:] == '__':
+                        continue
+                    attr = getattr(obj, name)
+                    if id(attr) not in self._visitedIds:
+                        self._visitedIds.add(id(attr))
+                        if self._examine(attr):
+                            self._id2pathStr[id(attr)] = self._id2pathStr[id(obj)] + '.%s' % name
+                            self._stack.push(attr)
+            if type(obj) not in (types.StringType, types.UnicodeType):
+                if type(obj) is types.DictType:
+                    keys = obj.keys()
+                    for key in keys:
+                        attr = obj[key]
+                        if id(attr) not in self._visitedIds:
+                            self._visitedIds.add(id(attr))
+                            if self._examine(attr):
+                                self._id2pathStr[id(attr)] = self._id2pathStr[id(obj)] + '[%s]' % safeRepr(key)
+                                self._stack.push(attr)
+                elif type(obj) is not types.FileType:
+                    try:
+                        itr = iter(obj)
+                    except:
+                        pass
+                    else:
+                        try:
+                            index = 0
+                            while 1:
+                                try:
+                                    attr = itr.next()
+                                except:
+                                    # some custom classes don't do well when iterated
+                                    break
+                                if id(attr) not in self._visitedIds:
+                                    self._visitedIds.add(id(attr))
+                                    if self._examine(attr):
+                                        self._id2pathStr[id(attr)] = self._id2pathStr[id(obj)] + '[%s]' % index
+                                        self._stack.push(attr)
+                                index += 1
+                        except StopIteration, e:
+                            pass
+        
+    def __repr__(self):
+        len2ids = invertDictLossless(self._id2len)
+        lengths = len2ids.keys()
+        lengths.sort()
+        lengths.reverse()
+        for l in lengths:
+            for id in len2ids[l]:
+                obj = self._id2container[id]
+                print '%s: %s: %s' % (l, repr(itype(obj)), self._id2pathStr[id])