Commits

Anonymous committed 4abcedd

see ChangeLog

  • Participants
  • Parent commits adb5238

Comments (0)

Files changed (9)

 17-03-2006 Martin Woudstra
-	python/trfutil.py: added class RDOFile
+	python/trfutil.py: 
+	    - added classes RDOFile,ESDFile,AODFile,PreJobOptionsFile,PostJobOptionsFile,
+	      RDBAccessOverride,SQLiteSupport
+	    - added functions append_path_env*, prepend_path_env*, find_datafile
 	python/basic_trfarg.py: 
 	    - fixed bug in ArgChoices.checkChoices(), made members private
 	    - InputDataFile.preRunAction() copies $POOLFILE. Serves as 
 	      baseclass for full input data args
 	    - new class OutputDataFile serves as baseclass of full output data args
 	python/full_trfarg.py:
-	    - Data file arguments now derive from In/OutDataFile base classes
-	    - Added classes InputRDOFile and OutputRDOFile
+	    - Data file arguments now derive from In/OutDataFileArg base classes
+	    - Added classes In/OutputRDOFileArg, In/OutputESDFileArg, In/OutputAODFileArg
+	python/trfconsts.py: new! Holds useful constants (were in trfenv.py before)
+	python/trf.py: 
+	    - added support for PreJobOptionsFile and PostJobOptionsFile
+	    - error communication between athena & trf now via exitStatusFile
 16-03-2006 Martin Woudstra
 	python/basic_trfarg.py: added class BoolArg
 14-03-2006 Martin Woudstra

File python/athena_wrapper.py

 from AthenaCommon.Include import IncludeError
 from AthenaCommon.Utils.unixtools import which
 
-from PyJobTransformsCore import trferr
-from PyJobTransformsCore import trfenv
+from PyJobTransformsCore import trferr,trfenv,trfconsts
 
 try:
-#    print '%s=%s' % (trfenv.PYTHONPATH, os.environ[trfenv.PYTHONPATH])
-#    print '%s=%s' % (trfenv.LD_LIBRARY_PATH, os.environ[trfenv.LD_LIBRARY_PATH])
-    sys.argv[0] = trfenv.athena_py
-    athena_exe = which(trfenv.athena_py)
+#    print '%s=%s' % (trfconsts.PYTHONPATH, os.environ[trfconsts.PYTHONPATH])
+#    print '%s=%s' % (trfconsts.LD_LIBRARY_PATH, os.environ[trfconsts.LD_LIBRARY_PATH])
+    sys.argv[0] = trfconsts.athena_py
+    athena_exe = which(trfconsts.athena_py)
     if not athena_exe:
-        trferr.exit( trferr.TRF_ENVIRONMENT_ERROR, '%s not found' % (trfenv.athena_py) )
+        trferr.exit( trferr.TRF_ENVIRONMENT_ERROR, '%s not found' % (trfconsts.athena_py) )
     execfile(athena_exe)
 
 #
 except exceptions.SystemExit, e:
     status = e.args[0]
     if status == 0:
-        sys.exit(0) # don't write exitstatus file
+        trferr.exit()
     else:
         trferr.exit( trferr.ATHENA_FAILURE_ERROR, 'SystemExit %d' % status )  
 
 #
 # If all else fails...
 #
-else:
+except:
     trferr.exit( trferr.UNKNOWN_EXCEPTION_RAISED, '%s: %s' % (e.__class__.__name__ ,e.args) )
     
+#
+# If no exception thrown, then all is OK?
+#
+trferr.exit()

File python/basic_trfarg.py

         InputFileArg.preRunAction(self)
         try:
             poolcatalog = os.environ['POOLFILE']
-        except:
-            pass  # should I throw an error?
+        except KeyError:
+            self._logger.warning( "Environment variable POOLFILE not set. %s not copied" % PoolDataFile.defaultCatalogFilename )
         else:
             self._logger.debug( "Copying file %s to %s" % (poolcatalog, PoolDataFile.defaultCatalogFilename) )
             shutil.copyfile( poolcatalog, PoolDataFile.defaultCatalogFilename )
-        
+
+        PoolDataFile.setMessageLevel(PoolDataFile.defaultMessageLevel,self._logger)
 
 
 class InputTarFileArg( InputFileArg ):
     def __init__(self,help,name,contents,type=PoolDataFile.defaultType):
         OutputFileArg.__init__(self,help,name,type,contents)
     
+
+    def preRunAction(self):
+        """Reduce POOL output message level"""
+        OutputFileArg.preRunAction(self)
+        PoolDataFile.setMessageLevel(PoolDataFile.defaultMessageLevel,self._logger)
+        

File python/full_trfarg.py

 import PyJobTransformsCore.basic_trfarg as trfarg
 from   PyJobTransformsCore.trfutil import *
 
-class InputEvgenFileArg(EvgenFile,trfarg.InputDataFileArg):
+class InputEvgenFileArg(trfarg.InputDataFileArg):
     """Input file that contains generated events"""
     def __init__(self,help='output data file with generated events',name='default',
                  contents=EvgenFile.defaultContents,type=EvgenFile.defaultType):
         return True
 
 
-class OutputEvgenFileArg(EvgenFile,trfarg.OutputDataFileArg):
+class OutputEvgenFileArg(trfarg.OutputDataFileArg):
     """Output file that contains generated events"""
     def __init__(self,help='output data file with generated events',name='default',
                  contents=EvgenFile.defaultContents,type=EvgenFile.defaultType):
 
 
 
-class InputHitsFileArg(HitsFile,trfarg.InputDataFileArg):
+class InputHitsFileArg(trfarg.InputDataFileArg):
     """Input file that contains hits"""
     def __init__(self,help='output data file with generated events',name='default',
                  contents=HitsFile.defaultContents,type=HitsFile.defaultType):
         return True
 
 
-class OutputHitsFileArg(HitsFile,trfarg.OutputDataFileArg):
+class OutputHitsFileArg(trfarg.OutputDataFileArg):
     """Output file that contains hits"""
     def __init__(self,help='output data file with generated events',name='default',
                  contents=HitsFile.defaultContents,type=HitsFile.defaultType):
         return True
 
 
-class InputRDOFileArg(RDOFile,trfarg.InputDataFileArg):
+class InputRDOFileArg(trfarg.InputDataFileArg):
     """Input file that contains RDO's"""
     def __init__(self,help='output data file with generated events',name='default',
                  contents=RDOFile.defaultContents,type=RDOFile.defaultType):
         return True
 
 
-class OutputRDOFileArg(RDOFile,trfarg.OutputDataFileArg):
+class OutputRDOFileArg(trfarg.OutputDataFileArg):
     """Output file that contains RDO's"""
     def __init__(self,help='output data file with generated events',name='default',
                  contents=RDOFile.defaultContents,type=RDOFile.defaultType):
         return True
 
 
+class InputESDFileArg(trfarg.InputDataFileArg):
+    """Input file that contains ESD's"""
+    def __init__(self,help='output data file with generated events',name='default',
+                 contents=ESDFile.defaultContents,type=ESDFile.defaultType):
+        trfarg.InputDataFileArg.__init__(self,help,name,contents,type)
 
-class OutputHistogramFileArg(HistogramFile,trfarg.OutputFileArg):
+    def isFullArgument(self):
+        return True
+
+
+class OutputESDFileArg(trfarg.OutputDataFileArg):
+    """Output file that contains ESD's"""
+    def __init__(self,help='output data file with generated events',name='default',
+                 contents=ESDFile.defaultContents,type=ESDFile.defaultType):
+        trfarg.OutputDataFileArg.__init__(self,help,name,contents,type)
+
+    def isFullArgument(self):
+        return True
+
+
+class InputAODFileArg(trfarg.InputDataFileArg):
+    """Input file that contains AOD's"""
+    def __init__(self,help='output data file with generated events',name='default',
+                 contents=AODFile.defaultContents,type=AODFile.defaultType):
+        trfarg.InputDataFileArg.__init__(self,help,name,contents,type)
+
+    def isFullArgument(self):
+        return True
+
+
+class OutputAODFileArg(trfarg.OutputDataFileArg):
+    """Output file that contains AOD's"""
+    def __init__(self,help='output data file with generated events',name='default',
+                 contents=AODFile.defaultContents,type=AODFile.defaultType):
+        trfarg.OutputDataFileArg.__init__(self,help,name,contents,type)
+
+    def isFullArgument(self):
+        return True
+
+
+class OutputHistogramFileArg(trfarg.OutputFileArg):
     """Output file that contains histograms."""
     def __init__(self,help='output histogram file',name='histogramFile',
                  contents=HistogramFile.defaultContents,type=HistogramFile.defaultType):
         return True
 
 
-class OutputNtupleFileArg(NtupleFile,trfarg.OutputFileArg):
+class OutputNtupleFileArg(trfarg.OutputFileArg):
     """Output file that contains ntuples."""
     def __init__(self,help='output ntuple file',name='ntupleFile',
                  contents=NtupleFile.defaultContents,type=NtupleFile.defaultType):

File python/trf.py

 
 from AthenaCommon.Logging import logging
 
-from PyJobTransformsCore import trfenv
-from PyJobTransformsCore import trferr
+from PyJobTransformsCore import trfenv,trferr,trfconsts
 from PyJobTransformsCore.trferr import *
 from PyJobTransformsCore.trfutil import *
 from PyJobTransformsCore.runargs import * 
         self._postRunActions.append( cmd )
 
 
+    def _addPreJobOptionsFile(self,jo):
+        self._preJobOptionsFiles.append( jo )
+
+
+    def _addPostJobOptionsFile(self,jo):
+        self._postJobOptionsFiles.append( jo )
+
+
     def setArgument(self,argName,argValue):
         """set value of an already defined argument"""
         key=argName.lower()
         if isinstance(arg1,Author): self.addAuthor(*vargs)
         if hasattr(arg1,'preRunAction'): self._addPreRunAction(arg1)
         if hasattr(arg1,'postRunAction'): self._addPostRunAction(arg1)
-
+        if isinstance(arg1,PreJobOptionsFile): self._addPreJobOptionsFile(arg1)
+        if isinstance(arg1,PostJobOptionsFile): self._addPostJobOptionsFile(arg1)
 
 
     def getRunArgsTemplate(self):
         # get joboptions search path
         # try to find the file in the search path
         if not find_joboptions( fn ):
-            raise TransformEnvError( 'Skeleton file %s not found in %s' % (fn,trfenv.JOBOPTIONSPATH) )
+            raise TransformEnvError( 'Skeleton file %s not found in %s' % (fn,trfconsts.JOBOPTIONSPATH) )
 
 
 
             #get/check the needed top jobOptions files
             self.ensureSkeleton()
             self.writeRunArgs()
-            for jo in self._preJobOptionsFiles + self._postJobOptionsFiles:
-                if not find_joboptions( jo ):
-                    raise TransformDefinitionError( "Top joboptions file %s not found" % (jo) )
+            athena = os.path.join( trfenv.trfPath, 'athena_wrapper.py' )
+            topOptions = [ self.runArgsFilename() ]
+            for jo in self._preJobOptionsFiles:
+                fn = jo.filename()
+                if fn: topOptions.append( fn ) 
+            topOptions += [ self.skeletonFilename() ]
+            for jo in self._postJobOptionsFiles:
+                fn = jo.filename()
+                if fn: topOptions.append( fn ) 
             # run the athena job
-            athena = os.path.join( trfenv.trfPath, 'athena_wrapper.py' )
-            jobOptions = [ self.runArgsFilename() ]
-            jobOptions += self._preJobOptionsFiles
-            jobOptions += [ self.skeletonFilename() ]
-            jobOptions += self._postJobOptionsFiles
-            syscommand = '%s %s 2>&1 | tee -a %s' % ( athena, ' '.join(jobOptions), self.logFilename() )
+            syscommand = '%s %s 2>&1 | tee -a %s' % \
+                         ( athena, ' '.join(topOptions), self.logFilename() )
             self._logger.debug( 'Executing %s' % (syscommand) )
-            status = os.system( syscommand ) >> 8 # status code is in upper byte of 16 bit word
-            if status != 0:
-                if Filename.exists(trferr.exitStatusFile):
-                    # error file is already written in athena_wrapper.py
-                    sys.exit( status )
-                else:
-                    trferr.exit( status, 'Unhandled athena exit code' )
+            os.system( syscommand )
+            status = trferr.ATHENA_OK
+            if Filename.exists(trferr.exitStatusFile):
+                # read error from file
+                exitFile = open( trferr.exitStatusFile )
+                status = trferr.ATHENA_FAILURE_ERROR
+                for line in exitFile:
+                    line = line.strip()
+                    beg = 0
+                    end = len(line)
+                    pos = beg
+                    while pos < end and line[pos].isdigit(): pos += 1
+                    if pos > beg: status = int(line[beg:pos])
+
+                exitFile.close()
+
+            # exit is case of failure of athena
+            if status != 0: sys.exit( status )
 
             # do all postRunActions
             self.exePostRunActions()

File python/trfconsts.py

+athena_py = 'athena.py'
+
+# names of some environment variables
+JOBOPTIONSPATH='JOBOPTSEARCHPATH'
+LD_PRELOAD = 'LD_PRELOAD'
+IFS = 'IFS'
+PYTHONPATH='PYTHONPATH'
+LD_LIBRARY_PATH='LD_LIBRARY_PATH'
+DATAPATH='DATAPATH'

File python/trfenv.py

 # prepare the runtime environment for the transformations
 import os,re
 from PyJobTransformsCore.trferr import *
+from PyJobTransformsCore import trfconsts
 
 # no imports out of scope!
 __all__ = [ ] 
 
-athena_py = 'athena.py'
 trfPath = os.path.dirname(__file__)
 
 #print 'using %s' % os.path.dirname(trfPath)
 
-#some constants to avoid typing errors
-JOBOPTIONSPATH='JOBOPTSEARCHPATH'
-LD_PRELOAD = 'LD_PRELOAD'
-IFS = 'IFS'
-PYTHONPATH='PYTHONPATH'
-LD_LIBRARY_PATH='LD_LIBRARY_PATH'
-
 # setup the run-time environment
 def setup_runtime():
     # check that LD_LIBRARY_PATH is set
     try:
-        os.environ[LD_LIBRARY_PATH]
+        os.environ[trfconsts.LD_LIBRARY_PATH]
     except KeyError:
         raise TransformEnvironmentError( 'LD_LIBRARY_PATH not set' )
     
     # add current dir to jo path
     try:
-        joPathEnv = os.environ[ JOBOPTIONSPATH ]
+        joPathEnv = os.environ[ trfconsts.JOBOPTIONSPATH ]
     except KeyError:
         jobOptionsPath = [ '' ]
     else:
         jobOptionsPath = re.split( ',|' + os.pathsep, joPathEnv )
         if '' not in jobOptionsPath:
             jobOptionsPath.insert(0, '')
-    os.environ[ JOBOPTIONSPATH ] = ','.join(jobOptionsPath)
+    os.environ[ trfconsts.JOBOPTIONSPATH ] = ','.join(jobOptionsPath)
     #
     # setting up some basic running environment (translated from athena.py)
     #
-    ifs = os.environ.get(IFS,'')
+    ifs = os.environ.get(trfconsts.IFS,'')
     ifs += ':'
-    os.environ[IFS] = ifs
+    os.environ[trfconsts.IFS] = ifs
     hepmc=''
     libHepMC_base_so = 'libHepMC_base.so'
-    for dir in os.environ[LD_LIBRARY_PATH].split(os.pathsep):
+    for dir in os.environ[trfconsts.LD_LIBRARY_PATH].split(os.pathsep):
         if os.path.exists( os.path.join( dir, libHepMC_base_so) ):
             hepmc=libHepMC_base_so
             break
     # for customized gcc dyncast and workaround for the HepMC_base/CLHEP problem
     # note: any other combination/order/syntax will crash valgrind 2.2.0
     try:
-        ld_preload = os.environ[LD_PRELOAD].split(os.pathsep)
+        ld_preload = os.environ[trfconsts.LD_PRELOAD].split(os.pathsep)
     except KeyError:
         ld_preload = [ ]
 
     ld_preload += [ "libAthenaServices.so", "libGaudiKernel.so" ]
     if hepmc: ld_preload += [ hepmc ]
-    os.environ[LD_PRELOAD] = os.pathsep.join(ld_preload)
+    os.environ[trfconsts.LD_PRELOAD] = os.pathsep.join(ld_preload)
 
 

File python/trferr.py

 exitStatusFile = 'exitstatus'
 
 TRF_OK = 0
+ATHENA_OK = 0
 ATHENA_FAILURE_ERROR = 1
 ATHENA_LOAD_DLL_ERROR = 3
 KEYBOARD_INTERRUPT = 4

File python/trfutil.py

-import os,sys,re,exceptions
+import os,sys,re,exceptions,shutil
 from AthenaCommon.Utils.unixtools import FindFile
+from PyJobTransformsCore import trfconsts
 
 
 def strip_suffix( aString, aSuffix ):
     return newString
 
 
+def append_path_env( env_name, what, sep=os.pathsep ):
+    """Append <what> to pathlike environment variable <env_name>.
+    (A list of paths separated by <sep>).
+    If environment variable does not yet exist, it will
+    be created and its value will be set that <what>"""
+    try:
+        var = os.environ[env_name]
+    except KeyError:
+        os.environ[env_name] = what
+        return
+    else:
+        os.environ[env_name] = var + sep + what
+
+
+def prepend_path_env( env_name, what, sep=os.pathsep ):
+    try:
+        var = os.environ[env_name]
+    except KeyError:
+        os.environ[env_name] = what
+        return
+    else:
+        os.environ[env_name] = what + sep + var
+
+
+def append_path_env_if( env_name, what, sep=os.pathsep ):
+    """As append_path_env, except that <what> is only appended if it
+    is not already present in the path."""
+    try:
+        var = os.environ[env_name]
+    except KeyError:
+        os.environ[env_name] = what
+        return
+    else:
+        if what not in var.split(sep):
+            os.environ[env_name] = var + sep + what
+    
+
+def prepend_path_env_if( env_name, what, sep=os.pathsep ):
+    try:
+        var = os.environ[env_name]
+    except KeyError:
+        os.environ[env_name] = what
+        return
+    else:
+        if what not in var.split(sep):
+            os.environ[env_name] = what + sep + var
+    
+
+def append_path_env_force( env_name, what, sep=os.pathsep ):
+    """As append_path_env, except that <what> will be removed
+    first if it is already present (not at the end)"""
+    try:
+        var = os.environ[env_name]
+    except KeyError:
+        os.environ[env_name] = what
+        return
+    else:
+        varList = var.split(sep)
+        try:
+            idx = varList.index(what)
+        except IndexError:
+            os.environ[env_name] = var + sep + what
+            return
+        else:
+            if idx != len(varList) - 1:
+                varList.remove(what)
+                varList.append(what)
+                os.environ[env_name] = sep.join(varList)
+                return
+
+
+def prepend_path_env_force( env_name, what, sep=os.pathsep ):
+    """As prepend_path_env, except that <what> will be removed
+    first if it is already present (not at the beginning)"""
+    try:
+        var = os.environ[env_name]
+    except KeyError:
+        os.environ[env_name] = what
+        return
+    else:
+        varList = var.split(sep)
+        try:
+            idx = varList.index(what)
+        except IndexError:
+            os.environ[env_name] = var + sep + what
+            return
+        else:
+            if idx != 0:
+                varList.remove(what)
+                varList.insert(0,what)
+                os.environ[env_name] = sep.join(varList)
+                return
+
+
+
 def find_file_env( filename, env_var_name ):
     try:
         env = os.environ[env_var_name]
         return FindFile( filename, re.split(',|' + os.pathsep, env ), os.R_OK )
 
 
+def find_datafile( filename ):
+    return find_file_env( trfconst.DATAPATH )
+
+
 def find_joboptions( jobOptionsFile ):
-    return find_file_env( os.path.expanduser( os.path.expandvars( jobOptionsFile ) ), 'JOBOPTSEARCHPATH' )
+    return find_file_env( os.path.expanduser( os.path.expandvars( jobOptionsFile ) ),
+                          trfconsts.JOBOPTIONSPATH )
 
 
 def find_library( lib ):
-    return find_file_env( os.path.expandvars( lib ), 'LD_LIBRARY_PATH' ) 
+    return find_file_env( os.path.expandvars( lib ), trfconsts.LD_LIBRARY_PATH ) 
 
 
 TRACEBACK_FILENAME = 0
 class PoolDataFile( Filename ):
     defaultType = 'pool.root'
     defaultCatalogFilename = 'PoolFileCatalog.xml'
+    defaultMessageLevel = 5
+
+    def setMessageLevel(level,logger=None):
+        os.environ['POOL_OUTMSG_LEVEL'] = str(level)
+        if logger is not None:
+            logger.info( "Setting POOL message level to %d" % level )
+    setMessageLevel = staticmethod(setMessageLevel)
+
+
 
 class EvgenFile:
     defaultContents = 'evgen'
 
 
 class RDOFile:
-    defaultContenst = 'rdo'
+    defaultContents = 'rdo'
     defaultType = PoolDataFile.defaultType
 
 
+class ESDFile:
+    defaultContents = 'esd'
+    defaultType = PoolDataFile.defaultType
+   
+
+class AODFile:
+    defaultContents = 'aod'
+    defaultType = PoolDataFile.defaultType
+   
+
 class HistogramFile:
     defaultContents = 'histo'
     defaultType = 'root'
         return self._filename
 
 
+    def setFilename(self,filename):
+        self._filename = filename
+
+
     def preRunAction(self):
-        if not find_joboptions( self._filename ):
+        """Check that joboptions file can be found.
+        Check is skipped if filename is empty"""
+        if self._filename and not find_joboptions( self._filename ):
             raise JobOptionsNotFoundError( self._filename )
     
+
+
+class PreJobOptionsFile(JobOptionsFile):
+    def __init__(self,filename):
+        JobOptionsFile.__init__(self,filename)
+
+
+    def preRunAction(self):
+        JobOptionsFile.preRunAction(self)
+
+
+
+class PostJobOptionsFile(JobOptionsFile):
+    def __init__(self,filename):
+        JobOptionsFile.__init__(self,filename)
+
+
+    def preRunAction(self):
+        JobOptionsFile.preRunAction(self)
+
+
+
+
+class RDBAccessOverride(PostJobOptionsFile):
+    """Override settings of RDBAccessSvc. Properties that can be overridden:
+    UseDBConnSvc,Technology,HostName.
+    Optionally the name of an environment variable can be given. If none
+    is given, the override is always applied. If one is given, the override is
+    applied only if the environment variable is defined. If the contents of the
+    environment variable is non-empty, it will be used to set the HostName field,
+    otherwise the defaultHostname will be used."""
+
+    def __init__(self,useDBConnSvc,technology,defaultHostname,environmentHostname=None):
+        """
+        useDBConnSvc: True or False (python objects, not strings). Will be used
+                      to set UseDBConnSvc to TRUE or FALSE.
+        technology:   string that is passed on to Technology
+        defaultHostname: used for HostName if environmentHostname if set to None,
+                      or if the value of the environment variable given by
+                      environmentHostname contains an empty string.
+        environmentHostname: If None (default), then override is always applied using
+                      defaultHostname for HostName. If a (string) value is given, its
+                      value is interpreted as a name of an environment variable. If
+                      the environment variable is not set at runtime, no override is
+                      applied. If the environment variable is set to an empty string,
+                      the overrride is applied using defaultHostname for HostName.
+                      If the environment variable is set to a non-empty string, the
+                      string is assigned to HostName."""
+
+        PostJobOptionsFile.__init__(self,"")
+        self._useDBConnSvc = useDBConnSvc
+        self._technology   = technology
+        self._defaultHost  = defaultHostname
+        self._environHost  = environmentHostname
+        self._usedHost = None
+
+
+    def setHostName(self,host):
+        self._usedHost = host
+
+
+    def getHostName(self):
+        if self._usedHost is None:
+            host = self._defaultHost
+            environHost = self._environHost
+            if environHost is not None:
+                hostEnv = os.environ.get(environHost,"")
+                if hostEnv: host = hostEnv
+            self._usedHost = host
+
+        return self._usedHost
+
+
+    def preRunAction(self):
+        """Create joboptions file to support SQLite for geometry database.
+        file if T_SQLITEGEOM environment
+        variable is set. Else set filename to empty string"""
+        # set the hostname
+        host = self.getHostName()
+        if environHost is not None and self._environHost not in os.environ.keys():
+            return
+
+        if os.path.isabs(host):
+            fulldb = host
+        else:
+            fulldb = find_datafile(host)
+       
+        if fulldb and os.path.exists(fulldb):
+            # convert UseDBConnSvc
+            if self._useDBConnSvc:
+                useConn = 'TRUE'
+            else:
+                useConn = 'FALSE'
+            # make jobOptions snippet
+            jo = [ '# override DB Access' ,
+                   'RDBAccessSvc = Service( "RDBAccessSvc" )' ,
+                   'RDBAccessSvc.UseDBConnSvc = %s' % (useConn) ,
+                   'RDBAccessSvc.Technology   = %r' % (self._technology) ,
+                   'RDBAccessSvc.HostName     = %r' % (host) ]
+            # make (hopefully) unique yet meaningful filename
+            filename = 'RDBAccessSvc_%s_%s_%s.py' % (useConn, self._technology,
+                                                     os.path.basename(host))
+        
+            joFile = open(filename)
+            joFile.write( os.linesep.join(jo) + os.linesep )
+            joFile.close()
+            self.setFilename(filename)
+
+        # only now call baseclass preRunAction()
+        PostJobOptionsFile.preRunAction(self)
+
+
+
+class SQLiteSupport(RDBAccessOverride):
+    """Overrides some proporties of RDBAccessSvc, to use sqlite database.
+    Makes and uses local copy of database to circumvent the problem that
+    only one user can use a database at a time. See also class RDBAccessOverride."""
+    def __init__(self,defaultHostname,environmentHostname=None):
+        """For meaning of arguments, see class RDBAccessOverride."""
+        RDBAccessOverride.__init__(self,False,"sqlite",defaultHostname,environmentHostname)
+
+
+    def preRunAction(self):
+        # an sqlite DB can only have one user at the time, so make a local copy of the db
+        # and prepend current path to DATAPATH, so it will be found first.
+        host = self.getHostName()
+        if os.path.isabs(host):
+            fulldb = host
+        else:
+            fulldb = find_datafile(host)
+        if fulldb and os.path.exists(fulldb):
+            host = os.path.basename(host)
+            shutil.copyfile(fulldb,host)
+            # prepend current path to DATAPATH, so this copy is found
+            # by PathResolver in RDBAccessSvc.
+            prepend_path_env_force(trfconsts.DATAPATH,os.curdir)
+            # override hostName to correspond to new situation
+            self.setHostName( host )
+
+        # only now call baseclass preRunAction
+        RDBAccessOverride.preRunAction(self)