diff -r d9a1e7939ee6 -r 635cfac73d28 repoapi.py --- a/repoapi.py Fri Jun 13 13:54:28 2014 +0200 +++ b/repoapi.py Tue Jun 10 16:01:49 2014 +0200 @@ -17,14 +17,12 @@ # with CubicWeb. If not, see . """Official API to access the content of a repository """ -from logilab.common.deprecation import deprecated +from logilab.common.deprecation import class_deprecated from cubicweb.utils import parse_repo_uri -from cubicweb import ConnectionError, ProgrammingError, AuthenticationError -from uuid import uuid4 -from contextlib import contextmanager -from cubicweb.req import RequestSessionBase -from functools import wraps +from cubicweb import ConnectionError, AuthenticationError +from cubicweb.server.session import Connection + ### private function for specific method ############################ @@ -65,7 +63,7 @@ session = repo._get_session(sessionid) # XXX the autoclose_session should probably be handle on the session directly # this is something to consider once we have proper server side Connection. - return ClientConnection(session, autoclose_session=True) + return Connection(session) def anonymous_cnx(repo): """return a ClientConnection for Anonymous user. @@ -82,292 +80,7 @@ # use vreg's repository cache return connect(repo, anon_login, password=anon_password) -def _srv_cnx_func(name): - """Decorate ClientConnection method blindly forward to Connection - THIS TRANSITIONAL PURPOSE - will be dropped when we have standalone connection""" - def proxy(clt_cnx, *args, **kwargs): - # the ``with`` dance is transitional. We do not have Standalone - # Connection yet so we use this trick to unsure the session have the - # proper cnx loaded. This can be simplified one we have Standalone - # Connection object - if not clt_cnx._open: - raise ProgrammingError('Closed client connection') - return getattr(clt_cnx._cnx, name)(*args, **kwargs) - return proxy - -def _open_only(func): - """decorator for ClientConnection method that check it is open""" - @wraps(func) - def check_open(clt_cnx, *args, **kwargs): - if not clt_cnx._open: - raise ProgrammingError('Closed client connection') - return func(clt_cnx, *args, **kwargs) - return check_open - - -class ClientConnection(RequestSessionBase): - """A Connection object to be used Client side. - - This object is aimed to be used client side (so potential communication - with the repo through RPC) and aims to offer some compatibility with the - cubicweb.dbapi.Connection interface. - - The autoclose_session parameter informs the connection that this session - has been opened explicitly and only for this client connection. The - connection will close the session on exit. - """ - # make exceptions available through the connection object - ProgrammingError = ProgrammingError - # attributes that may be overriden per connection instance - anonymous_connection = False # XXX really needed ? - is_repo_in_memory = True # BC, always true - - def __init__(self, session, autoclose_session=False): - super(ClientConnection, self).__init__(session.vreg) - self._session = session # XXX there is no real reason to keep the - # session around function still using it should - # be rewritten and migrated. - self._cnx = None - self._open = None - self._web_request = False - #: cache entities built during the connection - self._eid_cache = {} - self._set_user(session.user) - self._autoclose_session = autoclose_session - - def __enter__(self): - assert self._open is None - self._open = True - self._cnx = self._session.new_cnx() - self._cnx.__enter__() - self._cnx.ctx_count += 1 - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - self._open = False - self._cnx.ctx_count -= 1 - self._cnx.__exit__(exc_type, exc_val, exc_tb) - self._cnx = None - if self._autoclose_session: - # we have to call repo.close to ensure the repo properly forgets the - # session; calling session.close() is not enough :-( - self._session.repo.close(self._session.sessionid) - - - # begin silly BC - @property - def _closed(self): - return not self._open - - def close(self): - if self._open: - self.__exit__(None, None, None) - - def __repr__(self): - # XXX we probably want to reference the user of the session here - if self._open is None: - return '' - elif not self._open: - return '' - elif self.anonymous_connection: - return '' % self._cnx.connectionid - else: - return '' % self._cnx.connectionid - # end silly BC - - # Main Connection purpose in life ######################################### - - call_service = _srv_cnx_func('call_service') - - @_open_only - def execute(self, *args, **kwargs): - # the ``with`` dance is transitional. We do not have Standalone - # Connection yet so we use this trick to unsure the session have the - # proper cnx loaded. This can be simplified one we have Standalone - # Connection object - rset = self._cnx.execute(*args, **kwargs) - rset.req = self - return rset - - @_open_only - def commit(self, *args, **kwargs): - try: - return self._cnx.commit(*args, **kwargs) - finally: - self.drop_entity_cache() - - @_open_only - def rollback(self, *args, **kwargs): - try: - return self._cnx.rollback(*args, **kwargs) - finally: - self.drop_entity_cache() - - # security ################################################################# - - allow_all_hooks_but = _srv_cnx_func('allow_all_hooks_but') - deny_all_hooks_but = _srv_cnx_func('deny_all_hooks_but') - security_enabled = _srv_cnx_func('security_enabled') - - # direct sql ############################################################### - - system_sql = _srv_cnx_func('system_sql') - - # session data methods ##################################################### - - get_shared_data = _srv_cnx_func('get_shared_data') - set_shared_data = _srv_cnx_func('set_shared_data') - - @property - def transaction_data(self): - return self._cnx.transaction_data - - # meta-data accessors ###################################################### - - @_open_only - def source_defs(self): - """Return the definition of sources used by the repository.""" - return self._session.repo.source_defs() - - @_open_only - def get_schema(self): - """Return the schema currently used by the repository.""" - return self._session.repo.source_defs() - - @_open_only - def get_option_value(self, option): - """Return the value for `option` in the configuration.""" - return self._session.repo.get_option_value(option) - - entity_metas = _srv_cnx_func('entity_metas') - describe = _srv_cnx_func('describe') # XXX deprecated in 3.19 - - # undo support ############################################################ - - @_open_only - 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. - - Managers may filter according to user (eid) who has done the transaction - using the `ueid` argument. Others will only see their own transactions. - - Additional filtering capabilities is provided by using the following - named arguments: - - * `etype` to get only transactions creating/updating/deleting entities - of the given type - - * `eid` to get only transactions applied to entity of the given eid - - * `action` to get only transactions doing the given action (action in - 'C', 'U', 'D', 'A', 'R'). If `etype`, action can only be 'C', 'U' or - 'D'. - - * `public`: when additional filtering is provided, their are by default - only searched in 'public' actions, unless a `public` argument is given - and set to false. - """ - # the ``with`` dance is transitional. We do not have Standalone - # Connection yet so we use this trick to unsure the session have the - # proper cnx loaded. This can be simplified one we have Standalone - # Connection object - source = self._cnx.repo.system_source - txinfos = source.undoable_transactions(self._cnx, ueid, **actionfilters) - for txinfo in txinfos: - txinfo.req = req or self # XXX mostly wrong - return txinfos - - @_open_only - def transaction_info(self, txuuid, req=None): - """Return transaction object for the given uid. - - raise `NoSuchTransaction` if not found or if session's user is not - allowed (eg not in managers group and the transaction doesn't belong to - him). - """ - # the ``with`` dance is transitional. We do not have Standalone - # Connection yet so we use this trick to unsure the session have the - # proper cnx loaded. This can be simplified one we have Standalone - # Connection object - txinfo = self._cnx.repo.system_source.tx_info(self._cnx, txuuid) - if req: - txinfo.req = req - else: - txinfo.cnx = self - return txinfo - - @_open_only - def transaction_actions(self, txuuid, public=True): - """Return an ordered list of action effectued during that transaction. - - If public is true, return only 'public' actions, eg not ones triggered - under the cover by hooks, else return all actions. - - raise `NoSuchTransaction` if the transaction is not found or if - session's user is not allowed (eg not in managers group and the - transaction doesn't belong to him). - """ - # the ``with`` dance is transitional. We do not have Standalone - # Connection yet so we use this trick to unsure the session have the - # proper cnx loaded. This can be simplified one we have Standalone - # Connection object - return self._cnx.repo.system_source.tx_actions(self._cnx, txuuid, public) - - @_open_only - def undo_transaction(self, txuuid): - """Undo the given transaction. Return potential restoration errors. - - raise `NoSuchTransaction` if not found or if session's user is not - allowed (eg not in managers group and the transaction doesn't belong to - him). - """ - # the ``with`` dance is transitional. We do not have Standalone - # Connection yet so we use this trick to unsure the session have the - # proper cnx loaded. This can be simplified one we have Standalone - # Connection object - return self._cnx.repo.system_source.undo_transaction(self._cnx, txuuid) - - # cache management - - def entity_cache(self, eid): - return self._eid_cache[eid] - - def set_entity_cache(self, entity): - self._eid_cache[entity.eid] = entity - - def cached_entities(self): - return self._eid_cache.values() - - def drop_entity_cache(self, eid=None): - if eid is None: - self._eid_cache = {} - else: - del self._eid_cache[eid] - - # deprecated stuff - - @deprecated('[3.19] This is a repoapi.ClientConnection object not a dbapi one') - def request(self): - return self - - @deprecated('[3.19] This is a repoapi.ClientConnection object not a dbapi one') - def cursor(self): - return self - - @property - @deprecated('[3.19] This is a repoapi.ClientConnection object not a dbapi one') - def sessionid(self): - return self._session.sessionid - - @property - @deprecated('[3.19] This is a repoapi.ClientConnection object not a dbapi one') - def connection(self): - return self - - @property - @deprecated('[3.19] This is a repoapi.ClientConnection object not a dbapi one') - def _repo(self): - return self._session.repo +class ClientConnection(Connection): + __metaclass__ = class_deprecated + __deprecation_warning__ = '[3.20] %(cls)s is deprecated, use Connection instead'