I'll try to make a minimal reproducible sample of out if.

For autoflush, I tried putting manual flush lines between the commands
but the results were the same.

About exception, it is entering the exception block (I tried putting
print 'exception' there) but it is not catching it.

Zsolt

On 21 March 2016 at 11:20, Simon King <si...@simonking.org.uk> wrote:
> On Sat, Mar 19, 2016 at 3:44 AM, Zsolt Ero <zsolt....@gmail.com> wrote:
>>
>> My project is based on standard SQLAlchemy scaffold, ZTE, using ORM.
>> Pyramid 1.5.8.
>>
>> I'm trying to catch an IntegrityError (unique key constraint), I've made a
>> very minimal example
>>
>> @view_config(route_name='exception_test', renderer='json')
>> def exception_test(request):
>>     user = DBSession.query(User).filter(User.id == 1).first()
>>     user.tutorial_done = True
>>
>>     DBSession.query(Map).first()
>>
>>     map_obj = Map(user=request.user)
>>     map_obj.name = u'a'
>>     map_obj.slug = 'a'
>>
>>     try:
>>         DBSession.add(map_obj)
>>         DBSession.flush()
>>
>>     except Exception:
>>         return {'success': False}
>>
>>     return {
>>         'id': map_obj.id,
>>         'success': True
>>     }
>>
>>
>> This results in a InvalidRequestError, which cannot be catched, even with
>> an except Exception.
>>
>> 04:34:25,180 ERROR [waitress] Exception when serving /exception_test
>> Traceback (most recent call last):
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/waitress/channel.py",
>> line 336, in service
>>     task.service()
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/waitress/task.py",
>> line 169, in service
>>     self.execute()
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/waitress/task.py",
>> line 388, in execute
>>     app_iter = self.channel.server.application(env, start_response)
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/paste/translogger.py",
>> line 69, in __call__
>>     return self.application(environ, replacement_start_response)
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/pyramid/router.py",
>> line 242, in __call__
>>     response = self.invoke_subrequest(request, use_tweens=True)
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/pyramid/router.py",
>> line 217, in invoke_subrequest
>>     response = handle_request(request)
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/pyramid/tweens.py",
>> line 21, in excview_tween
>>     response = handler(request)
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/pyramid_tm/__init__.py",
>> line 101, in tm_tween
>>     reraise(*exc_info)
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/pyramid_tm/__init__.py",
>> line 90, in tm_tween
>>     manager.commit()
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/transaction/_manager.py",
>> line 111, in commit
>>     return self.get().commit()
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/transaction/_transaction.py",
>> line 280, in commit
>>     reraise(t, v, tb)
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/transaction/_transaction.py",
>> line 271, in commit
>>     self._commitResources()
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/transaction/_transaction.py",
>> line 417, in _commitResources
>>     reraise(t, v, tb)
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/transaction/_transaction.py",
>> line 394, in _commitResources
>>     rm.tpc_vote(self)
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/zope/sqlalchemy/datamanager.py",
>> line 103, in tpc_vote
>>     self.tx.commit()
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/sqlalchemy/orm/session.py",
>> line 390, in commit
>>     self._assert_active(prepared_ok=True)
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/sqlalchemy/orm/session.py",
>> line 214, in _assert_active
>>     % self._rollback_exception
>> InvalidRequestError: This Session's transaction has been rolled back due
>> to a previous exception during flush. To begin a new transaction with this
>> Session, first issue Session.rollback(). Original exception was:
>> (psycopg2.IntegrityError) duplicate key value violates unique constraint
>> "uq_maps_user_id"
>> DETAIL:  Key (user_id, slug)=(1, a) already exists.
>>
>> If I put a DBSession.rollback() in the exception block, it results in:
>>
>> 04:37:58,625 ERROR [waitress] Exception when serving /exception_test
>> Traceback (most recent call last):
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/waitress/channel.py",
>> line 336, in service
>>     task.service()
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/waitress/task.py",
>> line 169, in service
>>     self.execute()
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/waitress/task.py",
>> line 388, in execute
>>     app_iter = self.channel.server.application(env, start_response)
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/paste/translogger.py",
>> line 69, in __call__
>>     return self.application(environ, replacement_start_response)
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/pyramid/router.py",
>> line 242, in __call__
>>     response = self.invoke_subrequest(request, use_tweens=True)
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/pyramid/router.py",
>> line 217, in invoke_subrequest
>>     response = handle_request(request)
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/pyramid/tweens.py",
>> line 21, in excview_tween
>>     response = handler(request)
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/pyramid_tm/__init__.py",
>> line 101, in tm_tween
>>     reraise(*exc_info)
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/pyramid_tm/__init__.py",
>> line 90, in tm_tween
>>     manager.commit()
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/transaction/_manager.py",
>> line 111, in commit
>>     return self.get().commit()
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/transaction/_transaction.py",
>> line 280, in commit
>>     reraise(t, v, tb)
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/transaction/_transaction.py",
>> line 271, in commit
>>     self._commitResources()
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/transaction/_transaction.py",
>> line 417, in _commitResources
>>     reraise(t, v, tb)
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/transaction/_transaction.py",
>> line 394, in _commitResources
>>     rm.tpc_vote(self)
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/zope/sqlalchemy/datamanager.py",
>> line 103, in tpc_vote
>>     self.tx.commit()
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/sqlalchemy/orm/session.py",
>> line 390, in commit
>>     self._assert_active(prepared_ok=True)
>>   File
>> "/Users/user/.virtualenvs/maphub_web/lib/python2.7/site-packages/sqlalchemy/orm/session.py",
>> line 223, in _assert_active
>>     raise sa_exc.ResourceClosedError(closed_msg)
>> ResourceClosedError: This transaction is closed
>>
>>
>> Moreover, the weird part is that it all seems to depend on seemingly
>> meaningless (to me at least) order of the queries:
>>
>> Moving the query(Map) to be before user.tutorial_done
>>
>> user = DBSession.query(User).filter(User.id == 1).first()
>> DBSession.query(Map).first()
>> user.tutorial_done = True
>>
>> Results in the correct, catchable IntegrityError.
>>
>> However, removing the .filter() part makes it broken again:
>>
>> user = DBSession.query(User).first()
>> DBSession.query(Map).first()
>> user.tutorial_done = True
>>
>> What is happening here? I'm totally confused. Is this a bug in ZTE or
>> SQLAlchemy? How can I possibly run into an uncatchable exception in a view,
>> and if I do, what am I supposed to do?
>
>
> It's difficult to tell without a sample that we can run, but I think the
> exception is being raised after your view function returns. The zope
> transaction package (in combination with the pyramid_tm and
> pyramid_sqlalchemy packages) wraps each request to ensure that a transaction
> is either committed or rolled back at the end of the request. Your
> IntegrityError in the middle of the view is causing the transaction to be
> left in a broken state, but you aren't signalling that to the transaction
> manager. It has no way of knowing that an error has occurred in the view, so
> it tries to commit the transaction. Since this happens outside your view
> altogether, you can't catch it.
>
> The reason you get different behaviour when you order the statements
> differently is likely to be autoflush. By default, pending changes are
> flushed to the database whenever you issue a query (so in your original
> example, the call to DBSession.query(Map).first() will flush the
> user.tutorial_done change to the database).
>
> Hope that helps,
>
> Simon
>
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "pylons-devel" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/pylons-devel/NqHlZ52NPxU/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> pylons-devel+unsubscr...@googlegroups.com.
> To post to this group, send email to pylons-devel@googlegroups.com.
> Visit this group at https://groups.google.com/group/pylons-devel.
> For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google Groups 
"pylons-devel" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to pylons-devel+unsubscr...@googlegroups.com.
To post to this group, send email to pylons-devel@googlegroups.com.
Visit this group at https://groups.google.com/group/pylons-devel.
For more options, visit https://groups.google.com/d/optout.

Reply via email to