--- a/server/session.py Tue May 05 08:41:19 2015 +0200
+++ b/server/session.py Tue Jul 01 16:55:49 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2015 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -388,8 +388,9 @@
Database connection resources:
- :attr:`running_dbapi_query`, boolean flag telling if the executing query
- is coming from a dbapi connection or is a query from within the repository
+ :attr:`hooks_in_progress`, boolean flag telling if the executing
+ query is coming from a repoapi connection or is a query from
+ within the repository (e.g. started by hooks)
:attr:`cnxset`, the connections set to use to execute queries on sources.
If the transaction is read only, the connection set may be freed between
@@ -445,6 +446,7 @@
"""
is_request = False
+ hooks_in_progress = False
mode = 'read'
def __init__(self, session, cnxid=None, session_handled=False):
@@ -484,8 +486,6 @@
self._cnxset = None
#: CnxSetTracker used to report cnxset usage
self._cnxset_tracker = CnxSetTracker()
- #: is this connection from a client or internal to the repo
- self.running_dbapi_query = True
# internal (root) session
self.is_internal_session = isinstance(session.user, InternalManager)
@@ -526,7 +526,7 @@
self._set_user(session.user)
- # live cycle handling ####################################################
+ # life cycle handling ####################################################
def __enter__(self):
assert self._open is None # first opening
@@ -539,7 +539,18 @@
self.rollback()
self._open = False
+ @contextmanager
+ def running_hooks_ops(self):
+ """this context manager should be called whenever hooks or operations
+ are about to be run (but after hook selection)
+ It will help the undo logic record pertinent metadata or some
+ hooks to run (or not) depending on who/what issued the query.
+ """
+ prevmode = self.hooks_in_progress
+ self.hooks_in_progress = True
+ yield
+ self.hooks_in_progress = prevmode
# shared data handling ###################################################
@@ -943,27 +954,7 @@
@read_security.setter
@_open_only
def read_security(self, activated):
- oldmode = self._read_security
self._read_security = activated
- # running_dbapi_query used to detect hooks triggered by a 'dbapi' query
- # (eg not issued on the session). This is tricky since we the execution
- # model of a (write) user query is:
- #
- # repository.execute (security enabled)
- # \-> querier.execute
- # \-> repo.glob_xxx (add/update/delete entity/relation)
- # \-> deactivate security before calling hooks
- # \-> WE WANT TO CHECK QUERY NATURE HERE
- # \-> potentially, other calls to querier.execute
- #
- # so we can't rely on simply checking session.read_security, but
- # recalling the first transition from DEFAULT_SECURITY to something
- # else (False actually) is not perfect but should be enough
- #
- # also reset running_dbapi_query to true when we go back to
- # DEFAULT_SECURITY
- self.running_dbapi_query = (oldmode is DEFAULT_SECURITY
- or activated is DEFAULT_SECURITY)
# undo support ############################################################
@@ -1098,13 +1089,14 @@
if debug:
print self.commit_state, '*' * 20
try:
- while self.pending_operations:
- operation = self.pending_operations.pop(0)
- operation.processed = 'precommit'
- processed.append(operation)
- if debug:
- print operation
- operation.handle_event('precommit_event')
+ with self.running_hooks_ops():
+ while self.pending_operations:
+ operation = self.pending_operations.pop(0)
+ operation.processed = 'precommit'
+ processed.append(operation)
+ if debug:
+ print operation
+ operation.handle_event('precommit_event')
self.pending_operations[:] = processed
self.debug('precommit transaction %s done', self.connectionid)
except BaseException:
@@ -1121,14 +1113,15 @@
operation.failed = True
if debug:
print self.commit_state, '*' * 20
- for operation in reversed(processed):
- if debug:
- print operation
- try:
- operation.handle_event('revertprecommit_event')
- except BaseException:
- self.critical('error while reverting precommit',
- exc_info=True)
+ with self.running_hooks_ops():
+ for operation in reversed(processed):
+ if debug:
+ print operation
+ try:
+ operation.handle_event('revertprecommit_event')
+ except BaseException:
+ self.critical('error while reverting precommit',
+ exc_info=True)
# XXX use slice notation since self.pending_operations is a
# read-only property.
self.pending_operations[:] = processed + self.pending_operations
@@ -1138,16 +1131,17 @@
self.commit_state = 'postcommit'
if debug:
print self.commit_state, '*' * 20
- while self.pending_operations:
- operation = self.pending_operations.pop(0)
- if debug:
- print operation
- operation.processed = 'postcommit'
- try:
- operation.handle_event('postcommit_event')
- except BaseException:
- self.critical('error while postcommit',
- exc_info=sys.exc_info())
+ with self.running_hooks_ops():
+ while self.pending_operations:
+ operation = self.pending_operations.pop(0)
+ if debug:
+ print operation
+ operation.processed = 'postcommit'
+ try:
+ operation.handle_event('postcommit_event')
+ except BaseException:
+ self.critical('error while postcommit',
+ exc_info=sys.exc_info())
self.debug('postcommit transaction %s done', self.connectionid)
return self.transaction_uuid(set=False)
finally: