| Classes | Job Modules | Data Objects | Services | Algorithms | Tools | Packages | Directories | Tracs |

In This Package:

ProcessJobOptions.py

Go to the documentation of this file.
00001 import os, sys, re
00002 
00003 import logging
00004 _log = logging.getLogger(__name__)
00005 
00006 class LogFormatter(logging.Formatter):
00007     def __init__(self, fmt=None, datefmt=None, prefix = "# "):
00008         logging.Formatter.__init__(self, fmt, datefmt)
00009         self.prefix = prefix
00010     def format(self, record):
00011         fmsg = logging.Formatter.format(self, record)
00012         prefix = self.prefix
00013         if record.levelno >= logging.WARNING:
00014             prefix += record.levelname + ": "
00015         s = "\n".join([ prefix + line
00016                         for line in fmsg.splitlines() ])
00017         return s
00018 
00019 class LogFilter(logging.Filter):
00020     def __init__(self, name = ""):
00021         logging.Filter.__init__(self, name)
00022         self.printing_level = 0
00023         self.enabled = True
00024         self.threshold = logging.WARNING
00025     def filter(self, record):
00026         return record.levelno >= self.threshold or (self.enabled and self.printing_level <= 0)
00027     def printOn(self, step = 1, force = False):
00028         """
00029         Decrease the printing_level of 'step' units. ( >0 means no print)
00030         The level cannot go below 0, unless the force flag is set to True.
00031         A negative value of the treshold disables subsequent "PrintOff"s.
00032         """
00033         if force:
00034             self.printing_level -= step
00035         else:
00036             if self.printing_level > step:
00037                 self.printing_level -= step
00038             else:
00039                 self.printing_level = 0
00040     def printOff(self, step = 1):
00041         """
00042         Increase the printing_level of 'step' units. ( >0 means no print)
00043         """
00044         self.printing_level += step
00045     def disable(self, allowed = logging.WARNING):
00046         self.enabled = False
00047         self.threshold = allowed
00048     def enable(self, allowed = logging.WARNING):
00049         self.enabled = True
00050         self.threshold = allowed
00051 
00052 class ConsoleHandler(logging.StreamHandler):
00053     def __init__(self, strm = None, prefix = None):
00054         if strm is None:
00055             strm = sys.stdout
00056         if '2.7' in sys.version.split()[0]:
00057             logging.StreamHandler.__init__(self, stream = strm)
00058         else:
00059             logging.StreamHandler.__init__(self, strm = strm)
00060         if prefix is None:
00061             prefix = "# "
00062         self._filter = LogFilter(_log.name)
00063         self._formatter = LogFormatter(prefix = prefix)
00064         self.setFormatter(self._formatter)
00065         self.addFilter(self._filter)
00066     def setPrefix(self, prefix):
00067         self._formatter.prefix = prefix
00068     def printOn(self, step = 1, force = False):
00069         """
00070         Decrease the printing_level of 'step' units. ( >0 means no print)
00071         The level cannot go below 0, unless the force flag is set to True.
00072         A negative value of the treshold disables subsequent "PrintOff"s.
00073         """
00074         self._filter.printOn(step, force)
00075     def printOff(self, step = 1):
00076         """
00077         Increase the printing_level of 'step' units. ( >0 means no print)
00078         """
00079         self._filter.printOff(step)
00080     def disable(self, allowed = logging.WARNING):
00081         self._filter.disable(allowed)
00082     def enable(self, allowed = logging.WARNING):
00083         self._filter.enable(allowed)
00084 
00085 _consoleHandler = None
00086 def GetConsoleHandler(prefix = None):
00087     global _consoleHandler
00088     if _consoleHandler is None:
00089         _consoleHandler = ConsoleHandler(prefix = prefix)
00090     elif prefix is not None:
00091         _consoleHandler.setPrefix(prefix)
00092     return _consoleHandler
00093 
00094 def InstallRootLoggingHandler(prefix = None, level = None):
00095     root_logger = logging.getLogger()
00096     if not root_logger.handlers:
00097         root_logger.addHandler(GetConsoleHandler(prefix))
00098         root_logger.setLevel(logging.WARNING)
00099     if level is not None:
00100         root_logger.setLevel(level)
00101 
00102 def PrintOn(step = 1, force = False):
00103     GetConsoleHandler().printOn(step, force)
00104 def PrintOff(step = 1):
00105     GetConsoleHandler().printOff(step)
00106 
00107 class ParserError(RuntimeError):
00108     pass
00109 
00110 def _find_file(f):
00111     # expand environment variables in the filename 
00112     f = os.path.expandvars(f)
00113     if os.path.isfile(f):
00114         return os.path.realpath(f)
00115     
00116     path = os.environ.get('JOBOPTSEARCHPATH','').split(os.pathsep)
00117     # find the full path to the option file
00118     candidates = [d for d in path if os.path.isfile(os.path.join(d,f))]
00119     if not candidates:
00120         raise ParserError("Cannot find '%s' in %s" % (f,path))
00121     return os.path.realpath(os.path.join(candidates[0],f))
00122 
00123 _included_files = set()
00124 def _to_be_included(f):
00125     if f in _included_files:
00126         _log.warning("file '%s' already included, ignored.", f)
00127         return False
00128     _included_files.add(f)
00129     return True
00130 
00131 class JobOptsParser:
00132     comment = re.compile(r'(//.*)$')
00133     # non-perfect R-E to check if '//' is inside a string
00134     # (a tokenizer would be better)
00135     comment_in_string = re.compile(r'(["\']).*//.*\1') 
00136     directive = re.compile(r'^\s*#\s*([\w!]+)\s*(.*)\s*$')
00137     comment_ml = ( re.compile(r'/\*'), re.compile(r'\*/') )
00138     statement_sep = ";"
00139     reference = re.compile(r'^@([\w.]*)$')
00140     
00141     def __init__(self):
00142         # parser level states
00143         self.units = {}
00144         self.defines = {}
00145         if sys.platform != 'win32':
00146             self.defines[ "WIN32" ] = True
00147         
00148     def _include(self,file,function):
00149         file = _find_file(file)
00150         if _to_be_included(file):
00151             _log.info("--> Including file '%s'", file)
00152             function(file)
00153             _log.info("<-- End of file '%s'", file)
00154         
00155     def parse(self,file):
00156         # states for the "translation unit"
00157         statement = ""
00158         
00159         ifdef_level = 0
00160         ifdef_skipping = False
00161         ifdef_skipping_level = 0
00162         
00163         f = open(_find_file(file))
00164         l = f.readline()
00165         if l.startswith("#!"):
00166             # Skip the first line if it starts with "#!".
00167             # It allows to use options files as scripts.
00168             l = f.readline()
00169         
00170         while l:
00171             l = l.rstrip()+'\n' # normalize EOL chars (to avoid problems with DOS new-line on Unix)
00172             
00173             # single line comment
00174             m = self.comment.search(l)
00175             if m:
00176                 # check if the '//' is part of a string
00177                 m2 = self.comment_in_string.search(l)
00178                 # the '//' is part of a string if we find the quotes around it
00179                 # and they are not part of the comment itself  
00180                 if not ( m2 and m2.start() < m.start() ):
00181                     # if it is not the case, we can remove the comment from the
00182                     # statement 
00183                     l = l[:m.start()]+l[m.end():]
00184             # process directives
00185             m = self.directive.search(l)
00186             if m:
00187                 directive_name = m.group(1)
00188                 directive_arg = m.group(2).strip()
00189                 if directive_name == "include":
00190                     included_file = directive_arg.strip("'\"")
00191                     importOptions(included_file)
00192                 elif directive_name == "units":
00193                     units_file = directive_arg.strip("'\"")
00194                     self._include(units_file,self._parse_units)
00195                 elif directive_name in [ "ifdef", "ifndef"]:
00196                     ifdef_skipping_level = ifdef_level
00197                     ifdef_level += 1
00198                     if directive_arg in self.defines:
00199                         ifdef_skipping = directive_name == "ifndef"
00200                     else:
00201                         ifdef_skipping = directive_name == "ifdef"
00202                 elif directive_name == "else":
00203                     ifdef_skipping = not ifdef_skipping
00204                 elif directive_name == "endif":
00205                     ifdef_level -= 1
00206                     if ifdef_skipping and ifdef_skipping_level == ifdef_level:
00207                         ifdef_skipping = False
00208                 elif directive_name == "pragma":
00209                     if not directive_arg:
00210                         l = f.readline()
00211                         continue
00212                     pragma = directive_arg.split()
00213                     if pragma[0] == "print":
00214                         if len(pragma) > 1:
00215                             if pragma[1].upper() in [ "ON", "TRUE", "1" ]:
00216                                 PrintOn()
00217                             else:
00218                                 PrintOff()
00219                 else:
00220                     _log.warning("unknown directive '%s'", directive_name)
00221                 l = f.readline()
00222                 continue
00223             
00224             if ifdef_skipping:
00225                 l = f.readline()
00226                 continue
00227         
00228             # multi-line comment
00229             m = self.comment_ml[0].search(l)
00230             if m:
00231                 l,l1 = l[:m.start()],l[m.end():]
00232                 m = self.comment_ml[1].search(l1)
00233                 while not m:
00234                     l1 = f.readline()
00235                     if not l1:
00236                         break # EOF
00237                     m = self.comment_ml[1].search(l1)
00238                 if not l1 and not m:
00239                     raise ParserError("End Of File reached before end of multi-line comment")
00240                 l += l1[m.end():]
00241             
00242             if self.statement_sep in l:
00243                 i = l.index(self.statement_sep)
00244                 statement += l[:i]
00245                 self._eval_statement(statement.replace("\n","").strip())
00246                 statement = l[i+1:]
00247                 # it may happen (bug #37479) that the rest of the statement
00248                 # contains a comment.
00249                 if statement.lstrip().startswith("//"):
00250                     statement = ""
00251             else:
00252                 statement += l
00253             
00254             l = f.readline()
00255             
00256     def _parse_units(self,file):
00257         for line in open(file):
00258             if '//' in line:
00259                 line = line[:line.index('//')]
00260             line = line.strip()
00261             if not line:
00262                 continue
00263             nunit, value = line.split('=')
00264             factor, unit = nunit.split()
00265             value = eval(value)/eval(factor)
00266             self.units[unit] = value
00267 
00268     def _eval_statement(self,statement):
00269         from GaudiKernel.Proxy.Configurable import (ConfigurableGeneric,
00270                                                     Configurable,
00271                                                     PropertyReference)
00272         #statement = statement.replace("\n","").strip()
00273         _log.info("%s%s", statement, self.statement_sep)
00274         
00275         property,value = statement.split("=",1)
00276         
00277         inc = None
00278         if property[-1] in [ "+", "-" ]:
00279             inc = property[-1]
00280             property = property[:-1]
00281         
00282         property = property.strip()
00283         value = value.strip()
00284         
00285         ## find the configurable to apply the property to
00286         #parent_cfg = None
00287         #while '.' in property:
00288         #    component, property = property.split('.',1)
00289         #    if parent_cfg:
00290         #        if hasattr(parent_cfg,component):
00291         #            cfg = getattr(parent_cfg,component)
00292         #        else:
00293         #            cfg = ConfigurableGeneric(component)
00294         #            setattr(parent_cfg,component,cfg)
00295         #    else:
00296         #        cfg = ConfigurableGeneric(component)
00297         #    parent_cfg = cfg
00298         
00299         # remove spaces around dots
00300         property = '.'.join([w.strip() for w in property.split('.')])
00301         component, property = property.rsplit('.',1)
00302         if component in Configurable.allConfigurables:
00303             cfg = Configurable.allConfigurables[component]
00304         else:
00305             cfg = ConfigurableGeneric(component)
00306         
00307         #value = os.path.expandvars(value)
00308         value = value.replace('true','True').replace('false','False')
00309         if value[0] == '{' :
00310             # Try to guess if the values looks like a dictionary
00311             if ':' in value and not ( value[:value.index(':')].count('"')%2 or value[:value.index(':')].count("'")%2 ) :
00312                 # for dictionaries, keep the surrounding {}
00313                 value = '{'+value[1:-1].replace('{','[').replace('}',']')+'}'
00314             else : # otherwise replace all {} with []
00315                 value = value.replace('{','[').replace('}',']')
00316         
00317         # We must escape '\' because eval tends to interpret them 
00318         value = value.replace('\\','\\\\')
00319         
00320         # interprete the @ operator
00321         m = self.reference.match(value)
00322         if m:
00323             # this allows late binding of references
00324             value = PropertyReference(m.group(1))
00325         else:
00326             value = eval(value,self.units)
00327         
00328         #if type(value) is str    : value = os.path.expandvars(value)
00329         #elif type(value) is list : value = [ type(item) is str and os.path.expandvars(item) or item for item in value ]
00330     
00331         if property not in cfg.__slots__ and not hasattr(cfg,property):
00332             # check if the case of the property is wrong (old options are case insensitive)
00333             lprop = property.lower()
00334             for p in cfg.__slots__:
00335                 if lprop == p.lower():
00336                     _log.warning("property '%s' was requested for %s, but the correct spelling is '%s'", property, cfg.name(), p)
00337                     property = p
00338                     break
00339         
00340         # consider the += and -=
00341         if inc == "+":
00342             if hasattr(cfg,property):
00343                 prop = getattr(cfg,property)
00344                 if type(prop) == dict:
00345                     for k in value:
00346                         prop[k] = value[k]
00347                 else:
00348                     prop += value
00349             else:
00350                 setattr(cfg,property,value)
00351         elif inc == "-":
00352             if hasattr(cfg,property):
00353                 prop = getattr(cfg,property)
00354                 if type(prop) is dict:
00355                     for k in value:
00356                         if k in prop:
00357                             del prop[k]
00358                         else:
00359                             _log.warning("key '%s' not in %s.%s", k, cfg.name(), property)
00360                 else:
00361                     for k in value:
00362                         if k in prop:
00363                             prop.remove(k)
00364                         else:
00365                             _log.warning("value '%s' not in %s.%s", k, cfg.name(), property)
00366         else:
00367             setattr(cfg,property,value)
00368 
00369 class _TempSysPath:
00370     def __init__(self, new_path):
00371         self.old_path = sys.path
00372         sys.path = new_path
00373     def __del__(self):
00374         sys.path = self.old_path
00375 
00376 _parser = JobOptsParser()
00377 
00378 def _import_python(file):
00379     execfile(file, {})
00380 
00381 def _import_pickle(file):
00382     import pickle
00383     input = open(file, 'rb')
00384     catalog = pickle.load(input)
00385     _log.info('Unpickled %d configurables', len(catalog))
00386 
00387 def _import_opts(file):
00388     _parser.parse(file)
00389 
00390 _import_function_mapping = {
00391                              ".py"   : _import_python,
00392                              ".pkl"  : _import_pickle,
00393                              ".opts" : _import_opts,
00394                             }
00395 
00396 def importOptions( optsfile ) :
00397     # expand environment variables before checking the extension
00398     optsfile = os.path.expandvars(optsfile)
00399     # check the file type (extension)
00400     dummy, ext = os.path.splitext(optsfile)
00401     if ext in _import_function_mapping:
00402         # check if the file has been already included
00403         optsfile = _find_file(optsfile)
00404         if _to_be_included(optsfile):
00405             _log.info("--> Including file '%s'", optsfile)
00406             # include the file
00407             _import_function_mapping[ext](optsfile)
00408             _log.info("<-- End of file '%s'", optsfile)
00409     else:
00410         raise ParserError("Unknown file type '%s' ('%s')" % (ext,optsfile))
00411 
| Classes | Job Modules | Data Objects | Services | Algorithms | Tools | Packages | Directories | Tracs |

Generated on Mon Apr 11 19:56:58 2011 for GaudiKernel by doxygen 1.4.7