--- a/dbapi.py Tue Sep 14 08:48:44 2010 +0200
+++ b/dbapi.py Thu Sep 16 18:56:35 2010 +0200
@@ -457,6 +457,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
@@ -497,59 +503,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, else
- return its latest activity timestamp.
- """
- if self._closed is not None:
- raise ProgrammingError('Closed connection')
- return 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 get_shared_data(self, key, default=None, pop=False, txdata=False):
- """return value associated to key in the session's data dictionary or
- session's transaction's data if `txdata` is true.
-
- If pop is True, value will be removed from the dictionnary.
+ def __del__(self):
+ """close the remote connection if necessary"""
+ if self._closed is None and self._close_on_del:
+ try:
+ self.close()
+ except:
+ pass
- If key isn't defined in the dictionnary, value specified by the
- `default` argument will be returned.
- """
- if self._closed is not None:
- raise ProgrammingError('Closed connection')
- return self._repo.get_shared_data(self.sessionid, key, default, pop, txdata)
-
- def set_shared_data(self, key, value, txdata=False):
- """set value associated to `key` in shared data
-
- if `txdata` is true, the value will be added to the repository session's
- transaction's data which are cleared on commit/rollback of the current
- transaction.
- """
- if self._closed is not None:
- raise ProgrammingError('Closed connection')
- return self._repo.set_shared_data(self.sessionid, key, value, txdata)
-
- 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
@@ -605,20 +567,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:
@@ -634,19 +594,103 @@
user.cw_attr_cache['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, else
+ return its latest activity timestamp.
+ """
+ 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, txdata=False):
+ """return value associated to key in the session's data dictionary or
+ session's transaction's data if `txdata` is true.
+
+ If pop is True, value will be removed from the dictionnary.
+ If key isn't defined in the dictionnary, value specified by the
+ `default` argument will be returned.
+ """
+ return self._repo.get_shared_data(self.sessionid, key, default, pop, txdata)
+
+ @check_not_closed
+ def set_shared_data(self, key, value, txdata=False):
+ """set value associated to `key` in shared data
+
+ if `txdata` is true, the value will be added to the repository
+ session's query data which are cleared on commit/rollback of the current
+ transaction.
+ """
+ return self._repo.set_shared_data(self.sessionid, key, value, txdata)
+
+ # 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 get_option_value(self, option):
+ """return the value for `option` in the repository configuration."""
+ return self._repo.get_option_value(option)
+
+ @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).
@@ -656,52 +700,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.
@@ -734,6 +739,7 @@
txinfo.req = req
return txinfos
+ @check_not_closed
def transaction_info(self, txuuid, req=None):
"""Return transaction object for the given uid.
@@ -748,6 +754,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.
@@ -761,6 +768,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.