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

This commit is contained in:
Josh Wilson 2010-07-31 00:33:04 +00:00
parent 8fd806a5c9
commit 55955862aa
2 changed files with 233 additions and 0 deletions

View File

@ -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)

View File

@ -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
"""