Browse Source

adding ability to find all non-cyclic reference paths for a given object

Josh Wilson 15 years ago
parent
commit
55955862aa
2 changed files with 233 additions and 0 deletions
  1. 2 0
      direct/src/showbase/PythonUtil.py
  2. 231 0
      direct/src/showbase/ReferrerSearch.py

+ 2 - 0
direct/src/showbase/PythonUtil.py

@@ -2486,6 +2486,7 @@ def _getSafeReprNotify():
     global safeReprNotify
     from direct.directnotify.DirectNotifyGlobal import directNotify
     safeReprNotify = directNotify.newCategory("safeRepr")
+    return safeReprNotify
 
 def safeRepr(obj):
     global dtoolSuperBase
@@ -4138,6 +4139,7 @@ def startSuperLog(customFunction = None):
                 if customFunction:
                     superLogFile.write( "after = %s\n"%customFunction())
 
+        
 
                 return trace_dispatch
         sys.settrace(trace_dispatch)

+ 231 - 0
direct/src/showbase/ReferrerSearch.py

@@ -0,0 +1,231 @@
+import inspect
+import sys
+import gc
+from direct.showbase.PythonUtil import _getSafeReprNotify
+from direct.showbase.Job import Job
+
+class ReferrerSearch(Job):
+    def __init__(self, obj):
+        Job.__init__(self, 'ReferrerSearch')
+        self.obj = obj
+        self.found = set()
+    
+    def __call__(self):
+        safeReprNotify = _getSafeReprNotify()
+        info = safeReprNotify.getInfo()
+        safeReprNotify.setInfo(0)
+
+        self.found = set()
+        try:
+            self.step(0, [self.obj])
+        finally:
+            self.obj = None
+            pass
+        
+        safeReprNotify.setInfo(info)
+        pass
+
+    def run(self):
+        safeReprNotify = _getSafeReprNotify()
+        info = safeReprNotify.getInfo()
+        safeReprNotify.setInfo(0)
+
+        print 'RefPath: Beginning ReferrerSearch for', fastRepr(self.obj)
+
+        self.found = set()
+        for x in self.stepGenerator(0, [self.obj]):
+            yield None
+            pass
+        
+        self.obj = None
+        pass
+        
+        safeReprNotify.setInfo(info)
+
+        yield Job.Done
+        pass
+
+    def finished(self):
+        print 'RefPath: Completed ReferrerSearch for', fastRepr(self.obj)
+        self.obj = None
+        
+        
+    def truncateAtNewLine(self, s):
+        if s.find('\n') == -1:
+            return s
+        else:
+            return s[:s.find('\n')]
+        
+    def myrepr(self, referrer, refersTo):
+        pre = ''
+        if (isinstance(referrer, dict)):
+            for k,v in referrer.iteritems():
+                if v is refersTo:
+                    pre = self.truncateAtNewLine(fastRepr(k)) + ']-> '
+                    break
+        elif (isinstance(referrer, (list, tuple))):
+            for x in xrange(len(referrer)):
+                if referrer[x] is refersTo:
+                    pre = '%s]-> ' % (x)
+                    break
+
+        if (isinstance(refersTo, dict)):
+            post = 'dict['
+        elif (isinstance(refersTo, list)):
+            post = 'list['
+        elif (isinstance(refersTo, tuple)):
+            post = 'tuple['
+        elif (isinstance(refersTo, set)):
+            post = 'set->'
+        else:
+            post = self.truncateAtNewLine(fastRepr(refersTo)) + "-> "
+
+        return '%s%s' % (pre, post)
+        
+    def step(self, depth, path):
+        at = path[-1]
+
+        if inspect.isframe(at) or \
+           (isinstance(at, dict) and \
+            at.keys() == locals().keys()) or \
+           at is self.__dict__ or \
+           id(at) in self.found:
+               # don't continue down this path
+               return 
+
+        # Now we define our 'roots'
+
+        # __builtins__
+        if at is __builtins__:
+            sys.stdout.write("RefPath: __builtins__-> ")
+            path = list(reversed(path))
+            path.insert(0,0)
+            for x in xrange(len(path)-1):
+                sys.stdout.write(self.myrepr(path[x], path[x+1]))
+                pass
+            print
+            return
+
+        # any module scope
+        if inspect.ismodule(at):
+            sys.stdout.write("RefPath: Module(%s)-> " % (at.__name__))
+            path = list(reversed(path))
+            for x in xrange(len(path)-1):
+                sys.stdout.write(self.myrepr(path[x], path[x+1]))
+                pass
+            print
+            return
+
+        # simbase
+        if at is simbase:
+            sys.stdout.write("RefPath: simbase-> ")
+            path = list(reversed(path))
+            path.insert(0,0)
+            for x in xrange(len(path)-1):
+                sys.stdout.write(self.myrepr(path[x], path[x+1]))
+                pass
+            print
+            return
+
+        # simbase.air
+        if at is simbase.air:
+            sys.stdout.write("RefPath: simbase.air-> ")
+            path = list(reversed(path))
+            path.insert(0,0)
+            for x in xrange(len(path)-1):
+                sys.stdout.write(self.myrepr(path[x], path[x+1]))
+                pass
+            print
+            return
+        
+        self.found.add(id(at))
+        
+        referrers = gc.get_referrers(at)
+        while(referrers):
+            ref = referrers.pop()
+            if (ref != path):
+                self.step(depth + 1, path + [ref])
+            pass
+        pass
+    pass
+
+    def stepGenerator(self, depth, path):
+        at = path[-1]
+
+        if inspect.isframe(at) or \
+           (isinstance(at, dict) and \
+            at.keys() == locals().keys()) or \
+           at is self.__dict__ or \
+           id(at) in self.found:
+               # don't continue down this path
+               raise StopIteration 
+
+        # Now we define our 'roots'
+
+        # __builtins__
+        if at is __builtins__:
+            sys.stdout.write("RefPath: __builtins__-> ")
+            path = list(reversed(path))
+            path.insert(0,0)
+            for x in xrange(len(path)-1):
+                sys.stdout.write(self.myrepr(path[x], path[x+1]))
+                pass
+            print
+            raise StopIteration 
+
+        # any module scope
+        if inspect.ismodule(at):
+            sys.stdout.write("RefPath: Module(%s)-> " % (at.__name__))
+            path = list(reversed(path))
+            for x in xrange(len(path)-1):
+                sys.stdout.write(self.myrepr(path[x], path[x+1]))
+                pass
+            print
+            raise StopIteration
+
+        # simbase
+        if at is simbase:
+            sys.stdout.write("RefPath: simbase-> ")
+            path = list(reversed(path))
+            path.insert(0,0)
+            for x in xrange(len(path)-1):
+                sys.stdout.write(self.myrepr(path[x], path[x+1]))
+                pass
+            print
+            raise StopIteration
+
+        # simbase.air
+        if at is simbase.air:
+            sys.stdout.write("RefPath: simbase.air-> ")
+            path = list(reversed(path))
+            path.insert(0,0)
+            for x in xrange(len(path)-1):
+                sys.stdout.write(self.myrepr(path[x], path[x+1]))
+                pass
+            print
+            raise StopIteration        
+
+        self.found.add(id(at))
+        
+        referrers = gc.get_referrers(at)
+        while(referrers):
+            ref = referrers.pop()
+            if (ref != path):
+                for x in self.stepGenerator(depth + 1, path + [ref]):
+                    yield None
+                pass
+            pass
+
+        yield None
+        pass
+    pass
+
+
+"""
+from direct.showbase.ReferrerSearch import ReferrerSearch
+door = simbase.air.doFind("DistributedBuildingDoorAI")
+class A: pass
+door = A()
+ReferrerSearch()(door)
+reload(ReferrerSearch); from direct.showbase.PythonUtil import ReferrerSearch
+"""