Search code examples
pythonpandasexceptionpyodbc

How to catch a package-specific exception?


When I try to read a table from an SQL database with pandas using pandas.read_sql, the package pyodbc throws an DataError (pyodbc.DataError) that I would like to catch. The DataError is caused by an unexpected nvarchar value, causing an conversion failure when pyodbc attempts to convert it to data type int.

This is my code:

import pandas as pd 
import pyodbc
from sqlalchemy import create_engine
from sqlalchemy.engine import URL

driver = "SQL Server"
server = "my_server" 
database = "my_db" 

connection_string = (f"Driver={driver};"
                     f"Server={server};"
                     f"Database={database};"
                     f"Trusted_Connection=yes;"
                     f"TrustServerCertificate=yes")

connection_url = URL.create("mssql+pyodbc", 
                            query={"odbc_connect": connection_string})

engine = create_engine(connection_url)

# select only the first 10 rows in a table 
query = (f"SELECT top 10 * "
         f"FROM abc.table_name")

df = pd.read_sql(sql=query, 
             con=engine)

The output is

DataError: (pyodbc.DataError) ('22018', "[22018] [Microsoft][ODBC SQL Server Driver][SQL Server]Conversion failed when converting the nvarchar value '00:35' to data type int. (245) (SQLExecDirectW)")
[SQL: SELECT top 10 * FROM abc.table_name]
(Background on this error at: https://sqlalche.me/e/14/9h9h)

I know how to catch and handle built-in exceptions using try and except statements in Python. The DataError (pyodbc.DataError) however is not a built-in exception. I would like to catch this package-specific error while not just catching any error (I understand this to be bad practice).

I have attempted the following:

try: 
    df = pd.read_sql(sql=query, 
                 con=engine)
except DataError as err: 
    print(err)
    pass

This results in an NameError: name 'DataError' is not defined (as far as I understand, because DataError is not a built-in exception).

I have also attempted the following:

try: 
    df = pd.read_sql(sql=query, 
                 con=engine)
except pyodbc.DataError as err: 
    print(err)
    pass

This results in DataError: (pyodbc.DataError), because the error is not caught.


Solution

  • DataError seems to be an exception from SQLalchemy, see documentation: https://docs.sqlalchemy.org/en/20/core/exceptions.html#sqlalchemy.exc.DataError

    Try:

    from sqlalchemy.exc import DataError
    

    then

    try:
        df = pd.read_sql(sql=query, 
                     con=engine)
    except DataError as err: 
        print(err)
        pass