CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
List of all members | Public Member Functions | Private Attributes
TreeCrawler.mymf Class Reference
Inheritance diagram for TreeCrawler.mymf:

Public Member Functions

def __init__
 
def import_hook
 
def import_module
 
def load_module
 
def scan_opcodes_25
 

Private Attributes

 _depgraph
 
 _globalarea
 
 _last_caller
 
 _localarea
 
 _types
 

Detailed Description

Definition at line 91 of file TreeCrawler.py.

Constructor & Destructor Documentation

def TreeCrawler.mymf.__init__ (   self,
  args,
  kwargs 
)

Definition at line 92 of file TreeCrawler.py.

92 
93  def __init__(self,*args,**kwargs):
94  self._depgraph = {}
95  self._types = {}
96  self._last_caller = None
97  #TODO - replace by environment variables CMSSW_BASE and CMSSW_RELEASE_BASE (*and* do it only if the global one is not empty like for IB areas)
98  self._localarea = os.path.expandvars('$CMSSW_BASE')
99  self._globalarea = os.path.expandvars('$CMSSW_RELEASE_BASE')
modulefinder.ModuleFinder.__init__(self,*args,**kwargs)

Member Function Documentation

def TreeCrawler.mymf.import_hook (   self,
  name,
  caller = None,
  fromlist = None,
  level = -1 
)

Definition at line 100 of file TreeCrawler.py.

References TreeCrawler.mymf._last_caller.

101  def import_hook(self, name, caller=None, fromlist=None, level=-1):
102  old_last_caller = self._last_caller
103  try:
104  self._last_caller = caller
105  return modulefinder.ModuleFinder.import_hook(self,name,caller,fromlist, level=level)
106  finally:
107  self._last_caller = old_last_caller
def TreeCrawler.mymf.import_module (   self,
  partnam,
  fqname,
  parent 
)

Definition at line 108 of file TreeCrawler.py.

References TreeCrawler.mymf._globalarea, TreeCrawler.mymf._localarea, and python.rootplot.root2matplotlib.replace().

109  def import_module(self,partnam,fqname,parent):
110 
111  if partnam in ("os","unittest"):
112  r = None
113  else:
114  r = modulefinder.ModuleFinder.import_module(self,partnam,fqname,parent)
115  # since the modulefinder is not able to look into the global area when coming from the local area, we force a second try
116  if parent and not r and self._localarea != '' and self._globalarea != '':
117  parent.__file__ = parent.__file__.replace(self._localarea,self._globalarea)
118  parent.__path__[0] = parent.__path__[0].replace(self._localarea,self._globalarea)
119  r = modulefinder.ModuleFinder.import_module(self,partnam,fqname,parent)
120 
121  if r is not None:
122  self._depgraph.setdefault(self._last_caller.__name__,{})[r.__name__] = 1
return r
def TreeCrawler.mymf.load_module (   self,
  fqname,
  fp,
  pathname,
  suffix,
  mode,
  type 
)

Definition at line 123 of file TreeCrawler.py.

References TreeCrawler.mymf._types.

124  def load_module(self, fqname, fp, pathname, (suffix, mode, type)):
125  r = modulefinder.ModuleFinder.load_module(self, fqname, fp, pathname, (suffix, mode, type))
126  if r is not None:
127  self._types[r.__name__] = type
128  return r
def TreeCrawler.mymf.scan_opcodes_25 (   self,
  co,
  unpack = struct.unpack 
)
This is basically just the default opcode scanner from ModuleFinder, but extended to also
look for "process.load(<module>)' commands. Since the Process object might not necassarily
be called "process", it scans for a call to a "load" method with a single parameter on
*any* object. If one is found it checks if the parameter is a string that refers to a valid
python module in the local or global area. If it does, the scanner assumes this was a call
to a Process object and yields the module name.
It's not possible to scan first for Process object declarations to get the name of the
objects since often (e.g. for customisation functions) the object is passed to a function
in a different file.

The ModuleFinder.scan_opcodes_25 implementation this is based was taken from
https://hg.python.org/cpython/file/2.7/Lib/modulefinder.py#l364

Definition at line 129 of file TreeCrawler.py.

References TreeCrawler.mymf._globalarea, TreeCrawler.mymf._localarea, and timeUnitHelper.unpack().

130  def scan_opcodes_25(self, co, unpack = struct.unpack):
131  """
132  This is basically just the default opcode scanner from ModuleFinder, but extended to also
133  look for "process.load(<module>)' commands. Since the Process object might not necassarily
134  be called "process", it scans for a call to a "load" method with a single parameter on
135  *any* object. If one is found it checks if the parameter is a string that refers to a valid
136  python module in the local or global area. If it does, the scanner assumes this was a call
137  to a Process object and yields the module name.
138  It's not possible to scan first for Process object declarations to get the name of the
139  objects since often (e.g. for customisation functions) the object is passed to a function
140  in a different file.
141 
142  The ModuleFinder.scan_opcodes_25 implementation this is based was taken from
143  https://hg.python.org/cpython/file/2.7/Lib/modulefinder.py#l364
144  """
145  # Scan the code, and yield 'interesting' opcode combinations
146  # Python 2.5 version (has absolute and relative imports)
147  code = co.co_code
148  names = co.co_names
149  consts = co.co_consts
150  LOAD_CONST = modulefinder.LOAD_CONST
151  IMPORT_NAME = modulefinder.IMPORT_NAME
152  STORE_OPS = modulefinder.STORE_OPS
153  HAVE_ARGUMENT = modulefinder.HAVE_ARGUMENT
154  LOAD_ATTR = chr(dis.opname.index('LOAD_ATTR'))
155  LOAD_NAME = chr(dis.opname.index('LOAD_NAME'))
156  CALL_FUNCTION = chr(dis.opname.index('CALL_FUNCTION'))
157  LOAD_LOAD_AND_IMPORT = LOAD_CONST + LOAD_CONST + IMPORT_NAME
158 
159  try :
160  indexOfLoadConst = names.index("load") # This might throw a ValueError
161  # These are the opcodes required to access the "load" attribute. This might
162  # not even be a function, but I check for that later.
163  loadMethodOpcodes = LOAD_ATTR+struct.pack('<H',indexOfLoadConst)
164  except ValueError :
165  # doesn't look like "load" is used anywhere in this file
166  loadMethodOpcodes=None
167 
168  while code:
169  c = code[0]
170 
171  # Check to see if this is a call to a "load" method
172  if loadMethodOpcodes!=None and len(code)>=9 : # Need at least 9 codes for the full call
173  if code[:3]==loadMethodOpcodes :
174  # The attribute "load" is being accessed, need to make sure this is a function call.
175  # I'll look ahead and see if the CALL_FUNCTION code is used - this could be in a different
176  # place depending on the number of arguments, but I'm only interested in methods with a
177  # single argument so I know exactly where CALL_FUNCTION should be.
178  if code[6]==CALL_FUNCTION :
179  # I know this is calling a method called "load" with one argument. I need
180  # to find out what the argument is. Note that I still don't know if this is
181  # on a cms.Process object.
182  indexInTable=unpack('<H',code[4:6])[0]
183  if code[3]==LOAD_CONST :
184  # The argument is a constant, so retrieve that from the table
185  loadMethodArgument=consts[indexInTable]
186  # I know a load method with one argument has been called on *something*, but I don't
187  # know if it was a cms.Process object. All I can do is check to see if the argument is
188  # a string, and if so if it refers to a python file in the user or global areas.
189  try :
190  loadMethodArgument = loadMethodArgument.replace("/",".")
191  # I can only use imp.find_module on submodules (i.e. each bit between a "."), so try
192  # that on each submodule in turn using the previously found filename. Note that I have
193  # to try this twice, because if the first pass traverses into a package in the local
194  # area but the subpackage has not been checked out it will report that the subpackage
195  # doesn't exist, even though it is available in the global area.
196  try :
197  parentFilename=[self._localarea+"/python"]
198  for subModule in loadMethodArgument.split(".") :
199  moduleInfo=imp.find_module( subModule, parentFilename )
200  parentFilename=[moduleInfo[1]]
201  # If control got this far without raising an exception, then it must be a valid python module
202  yield "import", (None, loadMethodArgument)
203  except ImportError :
204  # Didn't work in the local area, try in the global area.
205  parentFilename=[self._globalarea+"/python"]
206  for subModule in loadMethodArgument.split(".") :
207  moduleInfo=imp.find_module( subModule, parentFilename )
208  parentFilename=[moduleInfo[1]]
209  # If control got this far without raising an exception, then it must be a valid python module
210  yield "import", (None, loadMethodArgument)
211  except Exception as error:
212  # Either there was an import error (not a python module) or there was a string
213  # manipulaton error (argument not a string). Assume this wasn't a call on a
214  # cms.Process object and move on silently.
215  pass
216 
217  elif code[3]==LOAD_NAME :
218  # The argument is a variable. I can get the name of the variable quite easily but
219  # not the value, unless I execute all of the opcodes. Not sure what to do here,
220  # guess I'll just print a warning so that the user knows?
221  print "Unable to determine the value of variable '"+names[indexInTable]+"' to see if it is a proces.load(...) statement in file "+co.co_filename
222 
223  code=code[9:]
224  continue
225 
226  if c in STORE_OPS:
227  oparg, = unpack('<H', code[1:3])
228  yield "store", (names[oparg],)
229  code = code[3:]
230  continue
231  if code[:9:3] == LOAD_LOAD_AND_IMPORT:
232  oparg_1, oparg_2, oparg_3 = unpack('<xHxHxH', code[:9])
233  level = consts[oparg_1]
234  if level == -1: # normal import
235  yield "import", (consts[oparg_2], names[oparg_3])
236  elif level == 0: # absolute import
237  yield "absolute_import", (consts[oparg_2], names[oparg_3])
238  else: # relative import
239  yield "relative_import", (level, consts[oparg_2], names[oparg_3])
240  code = code[9:]
241  continue
242  if c >= HAVE_ARGUMENT:
243  code = code[3:]
244  else:
245  code = code[1:]

Member Data Documentation

TreeCrawler.mymf._depgraph
private

Definition at line 93 of file TreeCrawler.py.

TreeCrawler.mymf._globalarea
private

Definition at line 98 of file TreeCrawler.py.

Referenced by TreeCrawler.mymf.import_module(), and TreeCrawler.mymf.scan_opcodes_25().

TreeCrawler.mymf._last_caller
private

Definition at line 95 of file TreeCrawler.py.

Referenced by TreeCrawler.mymf.import_hook().

TreeCrawler.mymf._localarea
private

Definition at line 97 of file TreeCrawler.py.

Referenced by TreeCrawler.mymf.import_module(), and TreeCrawler.mymf.scan_opcodes_25().

TreeCrawler.mymf._types
private

Definition at line 94 of file TreeCrawler.py.

Referenced by VarParsing.VarParsing.__getattr__(), VarParsing.VarParsing._convert(), TreeCrawler.mymf.load_module(), VarParsing.VarParsing.register(), and VarParsing.VarParsing.setType().