new search algorithm, replace function intervals, various improvements and speedups

This commit is contained in:
Joe Shochet 2006-06-15 16:56:12 +00:00
parent a6b5d75ce4
commit 405bf80de7

View File

@ -1,69 +1,31 @@
import time
import types import types
import os import os
import new import new
import sys
def findClassInModule(module, className, visited): def findClass(className):
# Make sure you have not already visited this module """
# to prevent recursion Look in sys.modules dictionary for a module that defines a class
if visited.has_key(module): with this className.
return None """
# Ok, clear to proceed, add this module to the visited list for moduleName, module in sys.modules.items():
visited[module] = 1 # Some modules are None for some reason
# print ('visiting: ' + `module`) if module:
# print "Searching in ", moduleName
# First see if we are in the dict at this level classObj = module.__dict__.get(className)
classObj = module.__dict__.get(className) # If this modules defines some object called classname and the
if classObj and ((type(classObj) == types.ClassType) or # object is a class or type definition and that class's module
(type(classObj) == types.TypeType)): # is the same as the module we are looking in, then we found
if classObj.__module__ == module.__name__: # the matching class and a good module namespace to redefine
return [classObj, module.__dict__] # our class in.
else: if (classObj and
# print "Must have found a module that imported this class", classObj, module ((type(classObj) == types.ClassType) or
pass (type(classObj) == types.TypeType)) and
(classObj.__module__ == moduleName)):
# Now filter out all the modules and iterate through them return [classObj, module.__dict__]
moduleList = filter(lambda value: type(value) == types.ModuleType, module.__dict__.values())
for moduleObj in moduleList:
ret = findClassInModule(moduleObj, className, visited)
# If that recursion found it, return the goodies
if ret:
return ret
# Well, after all that we did not find anything
return None return None
# Find a class named className somewhere in this namespace
def findClass(namespace, className):
# First see if we are in the namespace
classObj = namespace.get(className)
# print classObj, type(classObj)
if classObj and ((type(classObj) == types.ClassType) or
(type(classObj) == types.TypeType)):
return [classObj, namespace]
for key in namespace.keys():
value = namespace[key]
# If we found a class, see if it matches classname
# Make sure we do not match "_"
if ((key != "_") and ((type(value) == types.ClassType) or
(type(value) == types.TypeType))):
if value.__name__ == className:
# It does, that was easy!
return [value, namespace]
# Look in all the modules in this namespace
elif (type(value) == types.ModuleType):
ret = findClassInModule(value, className, {})
# If we found it return the goodies
if ret:
return ret
# Otherwise keep looking
# Nope, not in there
return None
def rebindClass(builtinGlobals, filename): def rebindClass(builtinGlobals, filename):
file = open(filename, 'r') file = open(filename, 'r')
lines = file.readlines() lines = file.readlines()
@ -83,96 +45,135 @@ def rebindClass(builtinGlobals, filename):
className = classHeader[:colonLoc] className = classHeader[:colonLoc]
else: else:
print 'error: className not found' print 'error: className not found'
# Remove that temp file
file.close()
os.remove(filename)
return return
print 'Rebinding class name: ' + className print 'Rebinding class name: ' + className
break break
# Store the original real class # Try to find the original class with this class name
res = findClass(builtinGlobals, className) res = findClass(className)
if res:
realClass, realNameSpace = res if not res:
else: print ('Warning: Finder could not find class')
# print ('Warning: could not find class, defining new class in builtins: ' + className) # Remove the temp file we made
# Now execute that class def
# execfile(filename, builtinGlobals)
print ('Warning: Finder could not find class, try importing the file first')
# Remove that temp file
file.close() file.close()
os.remove(filename) os.remove(filename)
return return
# Now execute that class def # Store the original real class
execfile(filename, realNameSpace) realClass, realNameSpace = res
# Remove that temp file
file.close()
os.remove(filename)
# Now execute that class def in this namespace
execfile(filename, realNameSpace)
# That execfile should have created a new class obj in that namespace
tmpClass = realNameSpace[className] tmpClass = realNameSpace[className]
# Copy the functions that we just redefined into the real class # Copy the functions that we just redefined into the real class
copyFuncs(tmpClass, realClass) copyFuncs(tmpClass, realClass)
# Now make sure the original class is in that namespace, not our temp one # Now make sure the original class is in that namespace,
# not our temp one from the execfile. This will help us preserve
# class variables and other state on the original class.
realNameSpace[className] = realClass realNameSpace[className] = realClass
# Remove the temp file we made
file.close()
os.remove(filename)
print (' Finished rebind') print (' Finished rebind')
def copyFuncs(fromClass, toClass): def copyFuncs(fromClass, toClass):
replaceFuncList = []
newFuncList = []
# Copy the functions from fromClass into toClass dictionary # Copy the functions from fromClass into toClass dictionary
for key in fromClass.__dict__.keys(): for funcName, newFunc in fromClass.__dict__.items():
value = fromClass.__dict__[key] # Filter out for functions
if (type(value) == types.FunctionType): if (type(newFunc) == types.FunctionType):
newFunc = value
# See if we already have a function with this name # See if we already have a function with this name
if toClass.__dict__.has_key(key): oldFunc = toClass.__dict__.get(funcName)
# Look in the messenger and taskMgr to see if this if oldFunc:
# old function pointer is stored there, replaceFuncList.append((oldFunc, funcName, newFunc))
# and update it to the new function pointer else:
oldFunc = toClass.__dict__[key] newFuncList.append((funcName, newFunc))
replaceMessengerFunc(oldFunc, newFunc)
replaceTaskMgrFunc(oldFunc, newFunc)
replaceStateFunc(oldFunc, newFunc)
replaceTcrFunc(oldFunc, newFunc)
# You cannot assign directly to the dict with new style classes
# toClass.__dict__[key] = newFunc
# Instead we will use setattr
setattr(toClass, key, newFunc)
def replaceMessengerFunc(oldFunc, newFunc): # Look in the messenger, taskMgr, and other globals that store func
# pointers to see if this old function pointer is stored there, and
# update it to the new function pointer.
replaceMessengerFunc(replaceFuncList)
replaceTaskMgrFunc(replaceFuncList)
replaceStateFunc(replaceFuncList)
replaceCRFunc(replaceFuncList)
replaceAIRFunc(replaceFuncList)
replaceIvalFunc(replaceFuncList)
# Now that we've the globals funcs, actually swap the pointers in
# the new class to the new functions
for oldFunc, funcName, newFunc in replaceFuncList:
# print "replacing old func: ", oldFunc, funcName, newFunc
setattr(toClass, funcName, newFunc)
# Add the brand new functions too
for funcName, newFunc in newFuncList:
# print "adding new func: ", oldFunc, funcName, newFunc
setattr(toClass, funcName, newFunc)
def replaceMessengerFunc(replaceFuncList):
try: try:
messenger messenger
except: except:
return return
res = messenger.replaceMethod(oldFunc, newFunc) for oldFunc, funcName, newFunc in replaceFuncList:
if res: res = messenger.replaceMethod(oldFunc, newFunc)
print 'replaced %d messenger functions: %s' % (res, newFunc.__name__) if res:
print ('replaced %s messenger function(s): %s' % (res, funcName))
def replaceTaskMgrFunc(oldFunc, newFunc): def replaceTaskMgrFunc(replaceFuncList):
try: try:
taskMgr taskMgr
except: except:
return return
res = taskMgr.replaceMethod(oldFunc, newFunc) for oldFunc, funcName, newFunc in replaceFuncList:
if res: if taskMgr.replaceMethod(oldFunc, newFunc):
print ('replaced taskMgr function: ' + newFunc.__name__) print ('replaced taskMgr function: %s' % funcName)
def replaceStateFunc(oldFunc, newFunc): def replaceStateFunc(replaceFuncList):
from direct.fsm import State if not sys.modules.get('direct.fsm.State'):
res = State.redefineEnterFunc(oldFunc, newFunc) return
if res: from direct.fsm.State import State
print ('replaced state enter function: ' + newFunc.__name__) for oldFunc, funcName, newFunc in replaceFuncList:
res = State.redefineExitFunc(oldFunc, newFunc) res = State.replaceMethod(oldFunc, newFunc)
if res: if res:
print ('replaced state exit function: ' + newFunc.__name__) print ('replaced %s FSM transition function(s): %s' % (res, funcName))
def replaceTcrFunc(oldFunc, newFunc): def replaceCRFunc(replaceFuncList):
try: try:
res = base.cr.replaceMethod(oldFunc, newFunc) base.cr
except: except:
try: return
res = simbase.air.replaceMethod(oldFunc, newFunc) for oldFunc, funcName, newFunc in replaceFuncList:
except: if base.cr.replaceMethod(oldFunc, newFunc):
res = None print ('replaced DistributedObject function: %s' % funcName)
if res:
print ('replaced DistributedObject function: ' + newFunc.__name__) def replaceAIRFunc(replaceFuncList):
try:
simbase.air
except:
return
for oldFunc, funcName, newFunc in replaceFuncList:
if simbase.air.replaceMethod(oldFunc, newFunc):
print ('replaced DistributedObject function: %s' % funcName)
def replaceIvalFunc(replaceFuncList):
# Make sure we have imported IntervalManager and thus created
# a global ivalMgr.
if not sys.modules.get('direct.interval.IntervalManager'):
return
from direct.interval.FunctionInterval import FunctionInterval
for oldFunc, funcName, newFunc in replaceFuncList:
res = FunctionInterval.replaceMethod(oldFunc, newFunc)
if res:
print ('replaced %s interval function(s): %s' % (res, funcName))