Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to catch integrity error with SQLAlchemy

I'm having problems with trying to catch an error. I'm using Pyramid/SQLAlchemy and made a sign up form with email as the primary key. The problem is when a duplicate email is entered it raises a IntegrityError, so I'm trying to catch that error and provide a message but no matter what I do I can't catch it, the error keeps appearing.

try:
    new_user = Users(email, firstname, lastname, password)
    DBSession.add(new_user)
    return HTTPFound(location = request.route_url('new'))
except IntegrityError:
    message1 = "Yikes! Your email already exists in our system. Did you forget your password?"

I get the same message when I tried except exc.SQLAlchemyError (although I want to catch specific errors and not a blanket catch all). I also tried exc.IntegrityError but no luck (although it exists in the API).

Is there something wrong with my Python syntax, or is there something I need to do special in SQLAlchemy to catch it?


I don't know how to solve this problem but I have a few ideas of what could be causing the problem. Maybe the try statement isn't failing but succeeding because SQLAlchemy is raising the exception itself and Pyramid is generating the view so the except IntegrityError: never gets activated. Or, more likely, I'm catching this error completely wrong.

like image 742
Lostsoul Avatar asked Jul 03 '12 15:07

Lostsoul


People also ask

What causes an integrity error?

"Data Integrity Error : The data structure from the page does not match the data structure in the database. This can be caused by a change in the record definition while you were viewing the page. This is a non-recoverable error and the current transaction will be aborted."

What is IntegrityError SQLAlchemy?

IntegrityError is a class within the sqlalchemy. exc module of the SQLAlchemy project.

What is SQLAlchemyError?

class ArgumentError(SQLAlchemyError): """Raised when an invalid or conflicting function argument is supplied. This error generally corresponds to construction time state errors.


2 Answers

In Pyramid, if you've configured your session (which the scaffold does for you automatically) to use the ZopeTransactionExtension, then session is not flushed/committed until after the view has executed. If you want to catch any SQL errors yourself in your view, you need to force a flush to send the SQL to the engine. DBSession.flush() should do it after the add(...).

Update

I'm updating this answer with an example of a savepoint just because there are very few examples around of how to do this with the transaction package.

def create_unique_object(db, max_attempts=3):
    while True:
        sp = transaction.savepoint()
        try:
            obj = MyObject()
            obj.identifier = uuid.uuid4().hex
            db.add(obj)
            db.flush()
        except IntegrityError:
            sp.rollback()
            max_attempts -= 1
            if max_attempts < 1:
                raise
        else:
            return obj

obj = create_unique_object(DBSession)

Note that even this is susceptible to duplicates between transactions if no table-level locking is used, but it at least shows how to use a savepoint.

like image 50
Michael Merickel Avatar answered Sep 24 '22 22:09

Michael Merickel


What you need to do is catch a general exception and output its class; then you can make the exception more specific.

except Exception as ex:
    print ex.__class__
like image 32
asthasr Avatar answered Sep 20 '22 22:09

asthasr