0

Is it possible to evaluate multiple conditions in a try block in Python. Below is the case. I have 2 conditions below.

  1. Connect to sql server to read data into two dataframes. There is a timeout in the code, if the connection takes more than 15 seconds the code should raise an exception and exit.
  2. Check if these two dataframe have data.If either one of the dataframes is empty, exit the code, if not continue the code in the else block.

I am currently thinking of doing like this. Is there more elegant way.

try:
    #Condition 1
except:
    #Condition 1
try:
    #Condition 2
except:
     #Condition 2

else:
    #Condition 3



def connect_to_server(table):
    # Connection Code
    server = '' 
    username = '' 
    password = '' 
    database = ''
    cnxn = pyodbc.connect('DRIVER={ODBC Driver 17 for SQL Server};SERVER='+server+';DATABASE='+database+';ENCRYPT=yes;UID='+username+';PWD='+ password)
    cnxn.timeout = 5   
    cursor = cnxn.cursor()
    try:
        cnxn.execute('SELECT * FROM ' +table)        
    except Exception as my_timeout_exception:
        raise my_timeout_exception
        
        
def read_database(table):
    server = '' 
    username = '' 
    password = '' 
    database = ''
    cnxn = pyodbc.connect('DRIVER={ODBC Driver 17 for SQL Server};SERVER='+server+';DATABASE='+database+';ENCRYPT=yes;UID='+username+';PWD='+ password)
    cursor = cnxn.cursor()
    df = pd.read_sql('SELECT * FROM '  +table, cnxn)
    if df.empty:
        print("dataframe is empty")
    else:
        return df
        
        
try:
    using_con = connect_to_server('table')
    df = read_database('table')
except my_timeout_exception:
    handle_error_1
    #break
except empty_df_exception: 
    handle_error_2
    #break
else:
    print("z")
SanjanaSanju
  • 261
  • 2
  • 18

2 Answers2

1

rIf you just want to capture different error conditions then you can include your code to connect to server and then test for data in the try statement. you then specify the error you want to catch in the except statement:

def connect_to_server(db):
    # Connection Code
    if connection_timed_out:
        raise my_timeout_exception #either a custom error you have created or propagate standard error from connection timeout
    return connection

def read_database(conn):
    #read db into dataframe code
    if dataframe_isempty:
        raise empty_df_exception #either a custom error you have created or propagate standard error from dataframe reading
    return dataframe

try:
    using_con = connect_to_server(db)
    df = read_database(using_con)
except my_timeout_exception:
    handle_error_1
    break
except empty_df_exception: 
    handle_error_2
    break
else:
    continue_code

You can actually include both exceptions in one except statement if the handling code is the same (eg just a break statement).

Galo do Leste
  • 703
  • 5
  • 13
  • Thanks for the reply. I tried the approach you suggested with a simple mathematical operations. I'm getting the below error. TypeError: catching classes that do not inherit from BaseException is not allowed – SanjanaSanju Jan 11 '23 at 01:27
  • Sounds like the exception you are trying to capture is not recognized as a proper exception. If you are using a custom exception (ie one you have created) note that the custom exception must be a class that inherits the standard Exception class. If this does not help or you do not understand it, please post a simple code example that gives you that error. Also read https://stackoverflow.com/questions/1319615/proper-way-to-declare-custom-exceptions-in-modern-python to give you some guidance creating custom exceptions – Galo do Leste Jan 11 '23 at 01:33
  • I have edited the code, Please help me understand. – SanjanaSanju Jan 11 '23 at 02:24
1

Fortunately pyodbc offers its own error classes so no need to create a custom one however we do create a custom error for an empty dataframe:

import pyodbc
import pandas as pd


class MyEmptyDfError(Exception):
    def __init__(self):
        message = "Dataframe is empty"
        super().__init__(message)


def connect_to_server():
    # Connection Code
    server = ''
    username = ''
    password = ''
    database = ''
    cnxn = pyodbc.connect('DRIVER={ODBC Driver 17 for SQL Server};SERVER='+server+';DATABASE='+database+';ENCRYPT=yes;UID='+username+';PWD='+ password)
    return cnxn


def read_database(table, cnxn):
    cnxn.timeout = 5
    df = pd.read_sql('SELECT * FROM ' + table, cnxn)
    if df.empty:
        raise MyEmptyDfError
    return df


try:
    conn = connect_to_server()
    df = read_database("test_table", conn)
except pyodbc.OperationalError as e:
    print(e)
except MyEmptyDfError as e:
    print(e)
finally:
    print("Final code reached")

Here if server connection triggers an error it propagates up to your code and is captured as OperatioalError (which I think is the error triggered if it times out) I think this should work (haven't been able to test it yet)

Galo do Leste
  • 703
  • 5
  • 13