Skip to content
Advertisement

Python try/finally wtih sys.exc_info()

I’m trying to write a python job that which I will be using in all the other jobs to capture the job start time and when a program finishes successfully or with some issues, I capture the error details and load the details into a table.

job_status

def srt(jobname):
   sts = 'running'
   df_srt = select(f'''select /'{job_name}/' as job_name, /'{strt_time}/' as strt_time, /'{sts}/' as sts''')
   df_srt.write.to_csv(/path_name)

def end(jobname):
   df_end = select(f'''select /'{job_name}/' as job_name, /'{strt_time}/' as strt_time, /'{end_time}/', /'{log}/' as log, /'{sts}/' as sts ''')
   df_end.write.to_csv(/path_name)

Program I’m using the job

from job_status import *

    def main_program:
       try:
          # some operation
          print(1/0)
       except:
         pass
       finally:
          if sys.exc_info()[0] is not None:
                status = 'Failed'
                log = concat(sys.exc_info()[0],' , ', sys.exc_info()[1], ' , ', sys.exc_info()[2])
                end_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                end(job_name=__name__, strt_time=start_time, end_time=end_time, sts=sts, log=log)
            else:
                sts = 'Success'
                end_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                end(job_name=__name__, start_time=start_time, end_time=end_time, status=status)

I’m trying to capture the error details, whenever a issue happens. But regardless the nature of the error, sys.exc_info()[0] goes to the success path. Any idea, How I can implement this?

Advertisement

Answer

(Note: A comment indicates that the code in the OP was not intended to catch an exception; rather, the intent was to just log the success or failure, and let the original exception propagate. The code here has been modified to accomplish that.)

The try command includes three types of additional clauses: except, else and finally:

  • "except" [expression ["as" identifier]]

    If an expression is provided, the clause is executed if an exception is thrown which matches the expression. If no expression is provided, the clause is executed if any exception is thrown.

  • else

    If no exception is thrown, the clause is executed.

  • finally

    The clause is executed at the end of the try block, after any matching except or else clause.

(See [Note 1] for the precise syntax. See the Python docs for more details.)

sys.exc_info can be used in an except clause (or in a function called during execution of an except clause) to extract information about the exception. Once the except clause finishes, sys.exc_info no longer returns useful information. Since the finally clause executes after the except clause has finished, that’s the case in your code.

But what you are trying to do with if exc_info is not None: is exactly what the try statement’s else clause does anyway. So you could have written your code somewhat more simply using an else clause. I did a little refactoring in order to be able to put common code in a finally clause.

In order to propagate the exception, it’s necessary to finish the except clause with a raise statement without an expression. This will cause the exception to continue “as though it were raised by the try block”. However, the finally clause is still executed before propagating.

def main_program:
    start_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    try:
        # some operation
        print(1/0)
    except:
        status = 'Failed'
        log = concat(sys.exc_info()[0],' , ', sys.exc_info()[1], ' , ', sys.exc_info()[2])
        raise
    else:
        status = 'Success'
        log = None
    finally:
        end_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        end(job_name=__name__, start_time=start_time, end_time=end_time, sts=sts, log=log)

Notes:

  1. The precise grammar of the try statement shows that you must have either at least one except clause or a finally clause, and that you can only have an else clause if you have an except clause. From the docs:
    try_stmt  ::=  try1_stmt | try2_stmt
    try1_stmt ::=  "try" ":" suite
                   ("except" [expression ["as" identifier]] ":" suite)+
                   ["else" ":" suite]
                   ["finally" ":" suite]
    try2_stmt ::=  "try" ":" suite
                   "finally" ":" suite
    
  2. I don’t know what concat is supposed to do here, so I just left it as is. It cannot be a simple string concatenation since the components of the tuple returned by sys.exc_info aren’t strings, and if that’s what you were looking for ', '.join(map(str, exc_info())) would work. If it’s some function which does nice formatting of the object returned by sys.exc_info, then you might consider just passing it the object returned by sys.exc_info.
User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement