00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 import sys, os, inspect, copy
00027 import modulefinder
00028
00029 def packageNameFromFilename(name):
00030 return ".".join(name.replace("python/","").replace(".py","").split("/")[-3:])
00031
00032
00033 class Color:
00034 """ANSI escape display sequences"""
00035 info = "\033[1;34m"
00036 hilight = "\033[31m"
00037 alternate = "\033[32m"
00038 extra = "\033[33m"
00039 backlight = "\033[43m"
00040 underline = "\033[4m"
00041 lessemphasis = "\033[30m"
00042 deemphasis = "\033[1;30m"
00043 none = "\033[0m"
00044
00045 _stack = []
00046
00047 class SearchHit:
00048 pass
00049
00050 class Package(object):
00051 def __init__(self,name,top=False):
00052 self.name = name
00053 self.dependencies = []
00054 self.searched = False
00055 self.stack = []
00056 if top:
00057 self.module = None
00058 else:
00059 self.module = __import__(name,[],[],"*")
00060 def dump(self,level):
00061 indent = " " * level
00062 print indent, "+", Color.info, self.name, Color.none
00063
00064 self.dependencies.sort(key = lambda x: x.name)
00065 for package in self.dependencies:
00066 package.dump(level+1)
00067 def search(self,pattern,result):
00068 """ recursive search for pattern in source files"""
00069
00070 if self.module:
00071 for number, line in enumerate(inspect.getsource(self.module).splitlines()):
00072 if pattern in line:
00073 filename = packageNameFromFilename(inspect.getsourcefile(self.module))
00074 if not self.searched:
00075
00076 self.hit = SearchHit()
00077 self.hit.number = number
00078 self.hit.filename = filename
00079 self.hit.line = line
00080 self.hit.stacks = list()
00081 result.append(self.hit)
00082 self.hit.stacks.append(copy.copy(_stack))
00083
00084 _stack.append(self.name)
00085 for package in self.dependencies:
00086 package.search(pattern,result)
00087 _stack.pop()
00088 self.searched = True
00089
00090
00091 class mymf(modulefinder.ModuleFinder):
00092 def __init__(self,*args,**kwargs):
00093 self._depgraph = {}
00094 self._types = {}
00095 self._last_caller = None
00096
00097 self._localarea = os.path.expandvars('$CMSSW_BASE')
00098 self._globalarea = os.path.expandvars('$CMSSW_RELEASE_BASE')
00099 modulefinder.ModuleFinder.__init__(self,*args,**kwargs)
00100 def import_hook(self, name, caller=None, fromlist=None):
00101 old_last_caller = self._last_caller
00102 try:
00103 self._last_caller = caller
00104 return modulefinder.ModuleFinder.import_hook(self,name,caller,fromlist)
00105 finally:
00106 self._last_caller = old_last_caller
00107
00108 def import_module(self,partnam,fqname,parent):
00109
00110 if partnam in ("FWCore","os"):
00111 r = None
00112 else:
00113 r = modulefinder.ModuleFinder.import_module(self,partnam,fqname,parent)
00114
00115 if parent and not r and self._localarea != '' and self._globalarea != '':
00116 parent.__file__ = parent.__file__.replace(self._localarea,self._globalarea)
00117 parent.__path__[0] = parent.__path__[0].replace(self._localarea,self._globalarea)
00118 r = modulefinder.ModuleFinder.import_module(self,partnam,fqname,parent)
00119
00120 if r is not None:
00121 self._depgraph.setdefault(self._last_caller.__name__,{})[r.__name__] = 1
00122 return r
00123 def load_module(self, fqname, fp, pathname, (suffix, mode, type)):
00124 r = modulefinder.ModuleFinder.load_module(self, fqname, fp, pathname, (suffix, mode, type))
00125 if r is not None:
00126 self._types[r.__name__] = type
00127 return r
00128
00129
00130 def transformIntoGraph(depgraph,toplevel):
00131 packageDict = {}
00132
00133 packageDict[toplevel] = Package(toplevel, top = True)
00134
00135
00136 for key, value in depgraph.iteritems():
00137 if key.count(".") == 2: packageDict[key] = Package(key)
00138 for name in value.keys():
00139 if name.count(".") == 2: packageDict[name] = Package(name)
00140
00141 for key, value in depgraph.iteritems():
00142 if key.count(".") == 2 or key == toplevel:
00143 package = packageDict[key]
00144 package.dependencies = [packageDict[name] for name in value.keys() if name.count(".") == 2]
00145
00146
00147 return packageDict[toplevel]
00148
00149
00150 def getDependenciesFromConfig(filename,toplevelname,path):
00151 imports = [filename]
00152 config = open(filename)
00153
00154 for line in config.readlines():
00155
00156 if line.startswith("process.load"):
00157 line = line.replace('"', "'")
00158 moduleName = line.split("'")[1]
00159 module = __import__(moduleName,[],[],"*")
00160 imports.append(inspect.getsourcefile(module))
00161 config.close()
00162
00163
00164 imports.sort(key= lambda x: x.split("python/")[-1])
00165
00166
00167 globalDependencyDict = {}
00168
00169
00170 for item in imports:
00171 modulefinder = mymf(path)
00172 modulefinder.run_script(item)
00173
00174 for key, value in modulefinder._depgraph.iteritems():
00175 if key == "__main__": key = packageNameFromFilename(item)
00176 globalDependencyDict[key] = value
00177
00178
00179 globalDependencyDict[toplevelname] = {}
00180 for item in imports:
00181 name = packageNameFromFilename(item)
00182 if name != toplevelname:
00183 globalDependencyDict[toplevelname][name] = 1
00184 return globalDependencyDict
00185
00186
00187 def getDependenciesFromPythonFile(filename,toplevelname,path):
00188 modulefinder = mymf(path)
00189 modulefinder.run_script(filename)
00190 globalDependencyDict = modulefinder._depgraph
00191 globalDependencyDict[toplevelname] = globalDependencyDict["__main__"]
00192 return globalDependencyDict
00193
00194
00195 def getImportTree(filename,path):
00196 config = __import__(filename.rstrip(".py"))
00197 toplevelname = packageNameFromFilename(filename)
00198
00199 if hasattr(config,"process"):
00200 globalDependencyDict = getDependenciesFromConfig(filename,toplevelname,path)
00201 else:
00202 globalDependencyDict = getDependenciesFromPythonFile(filename,toplevelname,path)
00203
00204 dependencyGraph = transformIntoGraph(globalDependencyDict,toplevelname)
00205 return dependencyGraph