I want to catch specific exceptions like UniqueViolation
on sqlalchemy.
But sqlalchemy throw exceptions only through IntegrityError
.
So I catched specific exceptions with below code.
except sqlalchemy.exc.IntegrityError as e:from psycopg2 import errorsif isinstance(e.orig, errors.UniqueViolation):passelif isinstance(e.orig, errors.ForeignKeyViolation):pass
But it looks doesn't elegant.
I don't want to using if statement just catch with specific exception name.
Is there any way to solve this issue?
Thanks.
You can reraise the original exception from the except
block and catch whatever specific type you are interested in:
import sqlalchemy
import psycopg2
from psycopg2 import errorstry:raise sqlalchemy.exc.IntegrityError("INSERT INTO table (col1) VALUES (?)", (1,), errors.IntegrityConstraintViolation)
except sqlalchemy.exc.IntegrityError as sqla_error:try:raise sqla_error.origexcept (errors.UniqueViolation, errors.ForeignKeyViolation):pass
This will raise all subclasses of psycopg2.IntegrityError
other than psycopg2.error.UniqueViolation
and psycopg2.errors.ForeignKeyViolation
.
As stated in SuperShoot's answer, this will result in a nested exception.
You can suppress the exception contex via:
raise sqla_error.orig from None
However, that might take away from the expressiveness of the traceback.
If you want to fall back to the SQLAlchemy IntegrityError if .orig
is not of a type you are interested in, you can raise it again by adding this to the above:
except psycopg2.IntegrityError:raise sqla_error from None