--- a/dbapi.py Wed Sep 15 18:43:14 2010 +0200
+++ b/dbapi.py Thu Sep 16 11:25:17 2010 +0200
@@ -459,6 +459,12 @@
time() - tstart, clock() - cstart))
return rset
+def check_not_closed(func):
+ def decorator(self, *args, **kwargs):
+ if self._closed is not None:
+ raise ProgrammingError('Closed connection')
+ return func(self, *args, **kwargs)
+ return decorator
class Connection(object):
"""DB-API 2.0 compatible Connection object for CubicWeb
@@ -499,51 +505,15 @@
self.rollback()
return False #propagate the exception
- def _txid(self, cursor=None): # XXX could now handle various isolation level!
- # return a dict as bw compat trick
- return {'txid': currentThread().getName()}
-
- def request(self):
- return DBAPIRequest(self.vreg, DBAPISession(self))
-
- def check(self):
- """raise `BadConnectionId` if the connection is no more valid"""
- if self._closed is not None:
- raise ProgrammingError('Closed connection')
- self._repo.check_session(self.sessionid)
-
- def set_session_props(self, **props):
- """raise `BadConnectionId` if the connection is no more valid"""
- if self._closed is not None:
- raise ProgrammingError('Closed connection')
- self._repo.set_session_props(self.sessionid, props)
+ def __del__(self):
+ """close the remote connection if necessary"""
+ if self._closed is None and self._close_on_del:
+ try:
+ self.close()
+ except:
+ pass
- def get_shared_data(self, key, default=None, pop=False):
- """return value associated to `key` in shared data"""
- if self._closed is not None:
- raise ProgrammingError('Closed connection')
- return self._repo.get_shared_data(self.sessionid, key, default, pop)
-
- def set_shared_data(self, key, value, querydata=False):
- """set value associated to `key` in shared data
-
- if `querydata` is true, the value will be added to the repository
- session's query data which are cleared on commit/rollback of the current
- transaction, and won't be available through the connexion, only on the
- repository side.
- """
- if self._closed is not None:
- raise ProgrammingError('Closed connection')
- return self._repo.set_shared_data(self.sessionid, key, value, querydata)
-
- def get_schema(self):
- """Return the schema currently used by the repository.
-
- This is NOT part of the DB-API.
- """
- if self._closed is not None:
- raise ProgrammingError('Closed connection')
- return self._repo.get_schema()
+ # connection initialization methods ########################################
def load_appobjects(self, cubes=_MARKER, subpath=None, expand=True):
config = self.vreg.config
@@ -599,20 +569,18 @@
if sitetitle is not None:
self.vreg['propertydefs']['ui.site-title'] = {'default': sitetitle}
+ @check_not_closed
def source_defs(self):
"""Return the definition of sources used by the repository.
This is NOT part of the DB-API.
"""
- if self._closed is not None:
- raise ProgrammingError('Closed connection')
return self._repo.source_defs()
+ @check_not_closed
def user(self, req=None, props=None):
"""return the User object associated to this connection"""
# cnx validity is checked by the call to .user_info
- if self._closed is not None:
- raise ProgrammingError('Closed connection')
eid, login, groups, properties = self._repo.user_info(self.sessionid,
props)
if req is None:
@@ -628,19 +596,90 @@
user['login'] = login # cache login
return user
- def __del__(self):
- """close the remote connection if necessary"""
- if self._closed is None and self._close_on_del:
- try:
- self.close()
- except:
- pass
+ @check_not_closed
+ def check(self):
+ """raise `BadConnectionId` if the connection is no more valid"""
+ self._repo.check_session(self.sessionid)
+
+ def _txid(self, cursor=None): # XXX could now handle various isolation level!
+ # return a dict as bw compat trick
+ return {'txid': currentThread().getName()}
+
+ def request(self):
+ return DBAPIRequest(self.vreg, DBAPISession(self))
+
+ # session data methods #####################################################
+
+ @check_not_closed
+ def set_session_props(self, **props):
+ """raise `BadConnectionId` if the connection is no more valid"""
+ self._repo.set_session_props(self.sessionid, props)
+ @check_not_closed
+ def get_shared_data(self, key, default=None, pop=False):
+ """return value associated to `key` in shared data"""
+ return self._repo.get_shared_data(self.sessionid, key, default, pop)
+
+ @check_not_closed
+ def set_shared_data(self, key, value, querydata=False):
+ """set value associated to `key` in shared data
+
+ if `querydata` is true, the value will be added to the repository
+ session's query data which are cleared on commit/rollback of the current
+ transaction, and won't be available through the connexion, only on the
+ repository side.
+ """
+ return self._repo.set_shared_data(self.sessionid, key, value, querydata)
+
+ # meta-data accessors ######################################################
+
+ @check_not_closed
+ def get_schema(self):
+ """Return the schema currently used by the repository."""
+ return self._repo.get_schema()
+
+ @check_not_closed
def describe(self, eid):
- if self._closed is not None:
- raise ProgrammingError('Closed connection')
return self._repo.describe(self.sessionid, eid, **self._txid())
+ # db-api like interface ####################################################
+
+ @check_not_closed
+ def commit(self):
+ """Commit pending transaction for this connection to the repository.
+
+ may raises `Unauthorized` or `ValidationError` if we attempted to do
+ something we're not allowed to for security or integrity reason.
+
+ If the transaction is undoable, a transaction id will be returned.
+ """
+ return self._repo.commit(self.sessionid, **self._txid())
+
+ @check_not_closed
+ def rollback(self):
+ """This method is optional since not all databases provide transaction
+ support.
+
+ In case a database does provide transactions this method causes the the
+ database to roll back to the start of any pending transaction. Closing
+ a connection without committing the changes first will cause an implicit
+ rollback to be performed.
+ """
+ self._repo.rollback(self.sessionid, **self._txid())
+
+ @check_not_closed
+ def cursor(self, req=None):
+ """Return a new Cursor Object using the connection.
+
+ On pyro connection, you should get cursor after calling if
+ load_appobjects method if desired (which you should call if you intend
+ to use ORM abilities).
+ """
+ if req is None:
+ req = self.request()
+ return self.cursor_class(self, self._repo, req=req)
+
+ @check_not_closed
def close(self):
"""Close the connection now (rather than whenever __del__ is called).
@@ -650,52 +689,13 @@
connection. Note that closing a connection without committing the
changes first will cause an implicit rollback to be performed.
"""
- if self._closed:
- raise ProgrammingError('Connection is already closed')
self._repo.close(self.sessionid, **self._txid())
del self._repo # necessary for proper garbage collection
self._closed = 1
- def commit(self):
- """Commit pending transaction for this connection to the repository.
-
- may raises `Unauthorized` or `ValidationError` if we attempted to do
- something we're not allowed to for security or integrity reason.
-
- If the transaction is undoable, a transaction id will be returned.
- """
- if not self._closed is None:
- raise ProgrammingError('Connection is already closed')
- return self._repo.commit(self.sessionid, **self._txid())
-
- def rollback(self):
- """This method is optional since not all databases provide transaction
- support.
-
- In case a database does provide transactions this method causes the the
- database to roll back to the start of any pending transaction. Closing
- a connection without committing the changes first will cause an implicit
- rollback to be performed.
- """
- if not self._closed is None:
- raise ProgrammingError('Connection is already closed')
- self._repo.rollback(self.sessionid, **self._txid())
-
- def cursor(self, req=None):
- """Return a new Cursor Object using the connection.
-
- On pyro connection, you should get cursor after calling if
- load_appobjects method if desired (which you should call if you intend
- to use ORM abilities).
- """
- if self._closed is not None:
- raise ProgrammingError('Can\'t get cursor on closed connection')
- if req is None:
- req = self.request()
- return self.cursor_class(self, self._repo, req=req)
-
# undo support ############################################################
+ @check_not_closed
def undoable_transactions(self, ueid=None, req=None, **actionfilters):
"""Return a list of undoable transaction objects by the connection's
user, ordered by descendant transaction time.
@@ -728,6 +728,7 @@
txinfo.req = req
return txinfos
+ @check_not_closed
def transaction_info(self, txuuid, req=None):
"""Return transaction object for the given uid.
@@ -742,6 +743,7 @@
txinfo.req = req
return txinfo
+ @check_not_closed
def transaction_actions(self, txuuid, public=True):
"""Return an ordered list of action effectued during that transaction.
@@ -755,6 +757,7 @@
return self._repo.transaction_actions(self.sessionid, txuuid, public,
**self._txid())
+ @check_not_closed
def undo_transaction(self, txuuid):
"""Undo the given transaction. Return potential restoration errors.