Source

mana-core-pyjobtransformscore / python / trferr.py

Full commit
################################################################################
# Exception classes
################################################################################
import exceptions,sys
from AthenaCommon.Logging import logging
from PyJobTransformsCore.trfutil import *

__all__ = [ 'TransformError', 'TransformDefinitionError', 'TransformArgumentError',
            'TransformEnvError', 'InputFileError', 'OutputFileError',
            'JobOptionsNotFoundError', 'TransformErrorHandler' ]

exitStatusFile = 'exitstatus'

TRF_OK = 0
ATHENA_FAILURE_ERROR = 1
ATHENA_LOAD_DLL_ERROR = 3
KEYBOARD_INTERRUPT = 4
JOBOPTIONS_NOT_FOUND = 5
JOBOPTIONS_PYTHON_ERROR = 6
TRF_INPUTFILE_ERROR = 20
TRF_ARGUMENT_ERROR = 30
TRF_DEFINITION_ERROR = 31
TRF_ENVIRONMENT_ERROR = 32
TRF_OUTPUTFILE_ERROR = 40
UNKNOWN_EXCEPTION_RAISED = 254
UNKWOWN_ERROR = 255

messages = { TRF_OK : 'OK' ,
             ATHENA_FAILURE_ERROR     : 'AthenaExitWithFailure'  ,
             ATHENA_LOAD_DLL_ERROR    : 'AthenaFailLoadLibrary' ,
             KEYBOARD_INTERRUPT       : 'KeyboardInterrupt' ,
             JOBOPTIONS_NOT_FOUND  : 'JobOptionsNotFound' ,
             JOBOPTIONS_PYTHON_ERROR : 'JobOptionsPythonError' ,
             TRF_INPUTFILE_ERROR   : 'TransformInputFileError'   ,
             TRF_ARGUMENT_ERROR    : 'TransformArgumentError'    ,
             TRF_DEFINITION_ERROR  : 'TransformDefinitionError'  ,
             TRF_ENVIRONMENT_ERROR : 'TransformEnvironmentError' ,
             TRF_OUTPUTFILE_ERROR  : 'TransformOutputFileError' ,
             UNKNOWN_EXCEPTION_RAISED : 'UnknownExceptionError'  ,
             UNKWOWN_ERROR            : 'UnknownError' }


def exit(status=0,message=None):
    statinfo = '%s %s' % (status,messages.get(status,'UnknownErrorCode'))
    if message: statinfo += ' # %s' % (message)
    if status: print 'ExitStatus: %s' % (statinfo)
    try:
        statfile = open(exitStatusFile,'w')
    except IOError:
        filename = os.path.basename(sys._getframe(1).f_code.co_filename)
        print '%s warning: could not write file %s', (filename, exitStatusFile)
        sys.exit(status)
    else:
        if status and sys.exc_info()[0]:
            import traceback
            traceback.print_exc()
        statfile.write( statinfo )
        statfile.write('\n')
        statfile.close()
        sys.exit(status)


class TransformError( exceptions.Exception ):
    """Base class for PyJobTransform Exception classes"""
    def __init__(self,msg=None,errnum=None):
        self.args = (errnum,msg)
        self.message = msg
        self.errnum = errnum


    def __str__(self):
        return '%s %d: %s' % (self.__class__.__name__, self.errnum, self.message)

    def exitStatus(self):
        return self.errnum


class TransformDefinitionError( TransformError ):
    """Exception raised in case of an error in the definition of the transformation"""
    def __init__(self,message=None,errnum=TRF_DEFINITION_ERROR):
        TransformError.__init__(self,message,errnum)


class TransformArgumentError( TransformError ):
    """Exception raised in case of an error in the argument values"""
    def __init__(self,message=None,errnum=TRF_ARGUMENT_ERROR):
        TransformError.__init__(self,message,errnum)


class TransformEnvError( TransformError ):
    """Exception raised in case of an error in the run-time environment"""
    def __init__(self,message=None,errnum=TRF_ENVIRONMENT_ERROR):
        TransformError.__init__(self,message,errnum)
        

class InputFileError( TransformArgumentError ):
    def __init__(self,filename,message=None,errnum=TRF_INPUTFILE_ERROR):
        mess = "Input file %s" % filename
        if message: mess += ' ' + message
        TransformArgumentError.__init__(self,mess,errnum) 
        self._filename = filename


    def filename(self):
        return self._filename
    

class OutputFileError( TransformArgumentError ):
    def __init__(self,filename,message=None,errnum=TRF_OUTPUTFILE_ERROR):
        mess = "Output file %s" % filename
        if message: mess += ' ' + message
        TransformArgumentError.__init__(self,mess,errnum) 
        self._filename = filename


    def filename(self):
        return self._filename
    


class JobOptionsNotFoundError( TransformError ):
    """Exception raised in case a joboptions file can not be found"""
    def __init__(self,filename,message=None,errnum=JOBOPTIONS_NOT_FOUND):
        mess = "JobOptions file %s not found" % filename
        if message: mess += '. ' + message
        TransformError.__init__(self,mess,errnum)


class TransformErrorHandler:
    def __init__(self):
        self._name = self.__class__.__name__
        self._context = ""
        self._setLogger()
 

    def name(self):
        return self._name


    def setLoggingContext(self,context):
        """Set the context string for the logger"""
        self._context = context
        self._setLogger()

        
    def setLoggingLevel(self,level):
        """Override the logging output level (instead the one of the context)"""
        self._logger.setLevel( level )
        

    def _setLogger(self):
        if self._context:
            name = '%s.%s' % (self._context,self._name)
        else:
            name = self._name
        self._logger = logging.getLogger( name )
        self._logger.setLevel( logging.DEBUG )


    def handleAthenaException(self,e):
        print "TransformErrorHandler.handleAthenaException(%s)..." % e.__class__.__name__
        if isinstance(e,exceptions.KeyboardInterrupt):
            self.handleKeyboardInterrupt(e)
        elif isinstance(e,exceptions.Exception):
            if hasattr(e,'args') and type(e.args) == type(list()) and e.args:
                args0 = e.args[0]
                argType0 = type(args0)
                # test for some known strings
                if argType0 == type(''):
                    if args0.find('Failed to load DLL') != -1:
                        self.handleDllLoadError(e)

                        
    def handleKeyboardInterrupt(self,e):
        exit(KEYBOARD_INTERRUPT)


    def handleDllLoadError(self,e):
        # try to find the guilty one
        mess = ""
        dllRE = "^theApp.Dlls\s*[+]?="
        stack = find_in_stack( dllRE )
        if stack:
            text = stack[TRACEBACK_TEXT]
            dllNameRE = "([\w\.\-]+)"
            subRE = "%s%s%s%s" % (dllRE,r"\s*\[\s*\"", dllNameRE, r"\"\s*\]")
            dll = re.sub( subRE, r"\1", text )
            lib = 'lib%s.so' % (dll)
            full_lib = find_library(lib)
            mess = 'module %s can not be loaded' % (dll)
            if not full_lib:
                mess = ' because %s can not be found' % (lib)
            else:
                self._logger.debug( "Found %s. Checking dependencies..." % full_lib )
                lddOut = os.popen( 'echo \"LD_LIBRARY_PATH=$LD_LIBRARY_PATH\"; ldd %s' % (full_lib) )
                missLibs = [ ]
                subRE = "%s%s%s" % (r"^\s*",dllNameRE,r"\s+.*not found\s*.*$")
                for line in lddOut:
                    if re.search( "not found", line ):
                        misLib = re.sub( subRE, r"\1", line )
                        missLibs.append( misLib )
                        fullMissLib = find_library(misLib)
                        if fullMissLib:
                            self._logger.debug( "ldd does not find %s, but I find it in %s" % (misLib, os.path.dirname(fullMissLib)) )
                            if not Filename.isReadable( fullMissLib ):
                                self._logger.debug( "%s found but can not be read" % (fullMissLib) )
                    elif re.search("LD_LIBRARY_PATH=", line ):
                        self._logger.debug( line )
                            
                lddOut.close()
                if len(missLibs) >= 1:
                    mess += ' because %s can not be found' % \
                            (', '.join(missLibs))
                        
                    
            exit( ATHENA_LOAD_DLL_ERROR, mess )

#
# end of class TransformErrorHandler:
#

defaultErrorHandler = TransformErrorHandler()

errorHandler = defaultErrorHandler