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,
  aux_info 
)

Definition at line 123 of file TreeCrawler.py.

References TreeCrawler.mymf._types.

124  def load_module(self, fqname, fp, pathname, aux_info):
125  (suffix, mode, type) = aux_info
126  r = modulefinder.ModuleFinder.load_module(self, fqname, fp, pathname, (suffix, mode, type))
127  if r is not None:
128  self._types[r.__name__] = type
129  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 130 of file TreeCrawler.py.

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

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