00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 __facility__ = "Online"
00011 __abstract__ = "GLAST LAT script engine related utility methods"
00012 __author__ = "S. Tuvi <stuvi@SLAC.Stanford.edu> SLAC - GLAST LAT I&T/Online"
00013 __date__ = "2005/07/23 00:08:27"
00014 __updated__ = "$Date: 2005/09/22 00:29:31 $"
00015 __version__ = "$Revision: 1.8 $"
00016 __release__ = "$Name: HEAD $"
00017 __credits__ = "SLAC"
00018
00019 import LICOS.copyright_SLAC
00020
00021 import imp
00022 import os
00023 import sys
00024 import logging as log
00025 import string
00026 from types import ModuleType
00027 from FSM import FSM
00028
00029 class Reloader:
00030 """!\brief Reloader class.
00031
00032 """
00033 DONT_RELOAD_LIST = ['scipy', 'weave', 'qwt', 'xml', 'pyexpat', 'win32',
00034 'ROOT', 'libPyROOT']
00035
00036 def __init__(self):
00037 """!\brief Reloader constructor.
00038
00039 """
00040 self.appinit = {}
00041
00042 def getNewModules(self, keepem):
00043 """!\brief Retrieve the new modules imported during the loading of the test.
00044
00045 \param keepem List of modules which should be excluded from the reloading.
00046 """
00047 modules = {}
00048 for i, m in sys.modules.items():
00049 if (i not in keepem) and \
00050 (type(m) == ModuleType):
00051 modules[i] = m
00052 return modules
00053
00054 def clearAppModules(self, dontReloadList, showUnloadedModules):
00055 """!\brief Unload modules that were loaded during the last test run.
00056
00057 \param dontReloadList List of module names which should not be unloaded
00058 \param showUnloadedModules Flag that indicates whether a debug log should
00059 be printed for each module that gets unloaded
00060 """
00061 if self.appinit == {}:
00062 appfinish = {}
00063 else:
00064 appfinish = self.getNewModules(self.appinit)
00065 for i in self.filterModules(appfinish, dontReloadList):
00066 if i in sys.modules:
00067 if showUnloadedModules:
00068 log.debug("Unloading module %s %s" % (i, sys.modules[i].__file__))
00069 del sys.modules[i]
00070 self.appinit = sys.modules.copy()
00071
00072 def filterModules(self, modules, dontReloadList):
00073 """!\brief Retrieve the list of modules that should be
00074 unloaded.
00075
00076 \param modules List of modules to be unloaded before filtering
00077 \param dontReloadList List of module names which should not be unloaded
00078 """
00079 dontReload = dontReloadList + Reloader.DONT_RELOAD_LIST
00080 mods = []
00081 for (moduleName, module) in modules.items():
00082 for modulePrefix in dontReload:
00083 if moduleName.startswith(modulePrefix):
00084 break
00085 if '__file__' not in dir(module):
00086 break
00087 if os.path.splitext(module.__file__)[1].lower() in ('.pyd','.dll'):
00088 break
00089 if os.path.normpath(os.path.normcase(module.__file__)).startswith(os.path.normpath(os.path.normcase(sys.prefix))):
00090 break
00091 else:
00092 mods.append(moduleName)
00093 return mods
00094
00095 reloadModules = Reloader()
00096
00097 def importModule(appName, reload=1, dontReloadList=[], showUnloadedModules=0):
00098 """!\brief Import a script engine application or suite.
00099
00100 \param appName Name of the module or pathname of the python script
00101 \param reload 1 = Reload all modules that have been loaded since
00102 the Script Engine started (default)
00103 0 = Do not reload modules (used if a suite is being loaded)
00104 \param dontReloadList Optional parameter which specifies the additional list
00105 of module prefixes that should not be reloaded. If this
00106 parameter is missing then the default list
00107 (Reloader.DONT_RELOAD_LIST) is used, if it is specified
00108 then it gets appended to the default list.
00109
00110 \return The name of the module and the resolved pathname
00111 """
00112
00113 (appPath, appFile) = os.path.split(appName)
00114 (appBase, appExt) = os.path.splitext(appFile)
00115 if appExt == '':
00116 try:
00117 if appPath == '':
00118 (f, path, desc) = imp.find_module(appBase)
00119 else:
00120 (f, path, desc) = imp.find_module(appBase, [appPath])
00121 (appPath, appFile) = os.path.split(path)
00122 (appBase, appExt) = os.path.splitext(appFile)
00123 except ImportError, e:
00124 raise e
00125
00126 _suffixes = {}
00127 for ext, mode, typ in imp.get_suffixes():
00128 _suffixes[ext] = (ext, mode, typ)
00129 _infoMap = {
00130 '.py' : ('.py','r',1),
00131 '.pyc': ('.pyc','rb',2),
00132 '.pyo': ('.pyo','rb',2)
00133 }
00134
00135
00136
00137
00138 curDir = os.getcwd()
00139 if appPath != '': os.chdir(appPath)
00140
00141
00142 appPath = os.getcwd()
00143 append = False
00144 if appPath not in sys.path:
00145 sys.path.append(appPath)
00146 append = True
00147 appName = os.path.join(appPath, appFile)
00148
00149 pycFile = os.path.join(appPath, appBase + '.pyc')
00150 pyoFile = os.path.join(appPath, appBase + '.pyo')
00151 if appExt == '.py':
00152 if os.path.exists(pyoFile) and os.path.getmtime(pyoFile) >= os.path.getmtime(appName):
00153 filename = pyoFile
00154 appExt = '.pyo'
00155 elif _suffixes.has_key('.pyo'):
00156 filename = appName
00157 elif os.path.exists(pycFile) and os.path.getmtime(pycFile) >= os.path.getmtime(appName):
00158 filename = pycFile
00159 appExt = '.pyc'
00160 else:
00161 filename = appName
00162 elif appExt == '.pyc':
00163 if os.path.exists(pyoFile) and os.path.getmtime(pyoFile) >= os.path.getmtime(appName):
00164 filename = pyoFile
00165 appExt = '.pyo'
00166 else:
00167 filename = appName
00168 elif appExt == '.pyo':
00169 filename = appName
00170 else:
00171 msg = 'Invalid module extension: %s' % appName
00172 raise RuntimeError, msg
00173 info = _infoMap[appExt]
00174 f = file(filename, info[1])
00175
00176 try:
00177
00178
00179 if reload: reloadModules.clearAppModules(dontReloadList, showUnloadedModules)
00180 module = imp.load_module(appBase, f, filename, info)
00181 finally:
00182 f.close()
00183 if append:
00184 sys.path.remove(appPath)
00185 if os.path.exists(curDir):
00186 os.chdir(curDir)
00187 return (module, filename)
00188
00189 def getMainClass(module):
00190 """!\brief Retrieve the main class of an application or suite.
00191
00192 Find out if the class inherits from FSM otherwise it is not the main class.
00193 If multiple main classes exist in one module then the one farthest away
00194 from FSM in the inheritance chain is used.
00195
00196 \param module Application or suite module
00197
00198 \return Main class or None
00199 """
00200 candidates = {}
00201 for objStr in dir(module):
00202 obj = getattr(module, objStr)
00203 if '__class__' in dir(obj) and getattr(obj,'__mro__',None) is not None:
00204 if FSM in obj.__mro__ and list(obj.__mro__).index(FSM) >= 2:
00205 candidates[obj] = list(obj.__mro__).index(FSM)
00206 if len(candidates) > 0:
00207 mainClass = None
00208 index = 0
00209 for (obj, fsmIndex) in candidates.items():
00210
00211
00212 if fsmIndex > index:
00213 mainClass = obj
00214 index = fsmIndex
00215 return mainClass
00216
00217 def scriptRun(app):
00218 """!\brief Run the test script or suite.
00219
00220 \return Status of the last transition executed
00221 """
00222 for transition in app.getRunSequence():
00223 status = app.process(transition)
00224 if status is not None:
00225 return status
00226
00227 def scriptLoad(script, common, reload=1, *args, **kwargs):
00228 """!\brief Load the script.
00229
00230 \param common ScriptEngineCommon instance
00231 \param reload Whether the reloading should be applied to the script.
00232 If reload=1, preference value is used, otherwise
00233 reloading is disabled
00234 \param args Positional arguments
00235 \param kwargs Keyword arguments
00236 """
00237 if common.options().noreload is not None:
00238 dontReloadList = common.getDBN()["_dontReload"]
00239 else:
00240 dontReloadList = []
00241 prefs = common.preferences()
00242 if prefs['dontreload'].strip() != "":
00243 dontReloadPrefs = map(string.strip, prefs['dontreload'].split(','))
00244 else:
00245 dontReloadPrefs = []
00246 dontReloadList += dontReloadPrefs
00247
00248
00249 if reload == 1:
00250 reload = not prefs["disablereload"]
00251 (module, filename) = importModule(appName=script,
00252 reload=reload,
00253 dontReloadList=dontReloadList,
00254 showUnloadedModules=prefs["showunloaded"] )
00255
00256 appClass = getMainClass(module)
00257
00258 if appClass is None:
00259 raise ImportError, "Application's base class does not inherit from FSM"
00260 else:
00261 return (module, filename, appClass(common, *args, **kwargs))