diff -r 838eaecaa458 -r d1030dd9730b server/session.py --- a/server/session.py Mon May 04 16:22:47 2009 +0200 +++ b/server/session.py Mon May 04 17:03:30 2009 +0200 @@ -13,7 +13,7 @@ from rql.nodes import VariableRef, Function, ETYPE_PYOBJ_MAP, etype_from_pyobj from yams import BASE_TYPES -from cubicweb import RequestSessionMixIn, Binary +from cubicweb import RequestSessionMixIn, Binary, UnknownEid from cubicweb.dbapi import ConnectionProperties from cubicweb.utils import make_uid from cubicweb.server.rqlrewrite import RQLRewriter @@ -29,7 +29,7 @@ continue if etype in BASE_TYPES: return True - return False + return False def _make_description(selected, args, solution): """return a description for a result set""" @@ -45,7 +45,7 @@ """tie session id, user, connections pool and other session data all together """ - + def __init__(self, user, repo, cnxprops=None, _id=None): super(Session, self).__init__(repo.vreg) self.id = _id or make_uid(user.login.encode('UTF8')) @@ -65,7 +65,7 @@ # i18n initialization self.set_language(cnxprops.lang) self._threaddata = threading.local() - + def get_mode(self): return getattr(self._threaddata, 'mode', 'read') def set_mode(self, value): @@ -78,12 +78,12 @@ def set_commit_state(self, value): self._threaddata.commit_state = value commit_state = property(get_commit_state, set_commit_state) - + # set according to transaction mode for each query @property def pool(self): return getattr(self._threaddata, 'pool', None) - + # pending transaction operations @property def pending_operations(self): @@ -92,7 +92,7 @@ except AttributeError: self._threaddata.pending_operations = [] return self._threaddata.pending_operations - + # rql rewriter @property def rql_rewriter(self): @@ -101,7 +101,7 @@ except AttributeError: self._threaddata._rewriter = RQLRewriter(self.repo.querier, self) return self._threaddata._rewriter - + # transaction queries data @property def _query_data(self): @@ -110,7 +110,7 @@ except AttributeError: self._threaddata._query_data = {} return self._threaddata._query_data - + def set_language(self, language): """i18n configuration for translation""" vreg = self.vreg @@ -124,42 +124,42 @@ except KeyError: self._ = self.__ = unicode self.lang = language - + def change_property(self, prop, value): assert prop == 'lang' # this is the only one changeable property for now self.set_language(value) def __str__(self): - return '<%ssession %s (%s 0x%x)>' % (self.cnxtype, self.user.login, + return '<%ssession %s (%s 0x%x)>' % (self.cnxtype, self.user.login, self.id, id(self)) def etype_class(self, etype): """return an entity class for the given entity type""" return self.vreg.etype_class(etype) - + def entity(self, eid): """return a result set for the given eid""" return self.eid_rset(eid).get_entity(0, 0) - + def _touch(self): """update latest session usage timestamp and reset mode to read """ self.timestamp = time() self.local_perm_cache.clear() self._threaddata.mode = 'read' - + def set_pool(self): """the session need a pool to execute some queries""" if self.pool is None: self._threaddata.pool = self.repo._get_pool() - try: + try: self._threaddata.pool.pool_set(self) except: self.repo._free_pool(self.pool) self._threaddata.pool = None raise return self._threaddata.pool - + def reset_pool(self): """the session has no longer using its pool, at least for some time """ @@ -170,7 +170,7 @@ self.repo._free_pool(self.pool) self.pool.pool_reset(self) self._threaddata.pool = None - + def system_sql(self, sql, args=None): """return a sql cursor on the system database""" if not sql.split(None, 1)[0].upper() == 'SELECT': @@ -181,26 +181,26 @@ def actual_session(self): """return the original parent session if any, else self""" - return self + return self # shared data handling ################################################### - + def get_shared_data(self, key, default=None, pop=False): """return value associated to `key` in session data""" if pop: return self.data.pop(key, default) else: return self.data.get(key, default) - + def set_shared_data(self, key, value, querydata=False): """set value associated to `key` in session data""" if querydata: self.set_query_data(key, value) else: self.data[key] = value - + # request interface ####################################################### - + def set_entity_cache(self, entity): # no entity cache in the server, too high risk of inconsistency # between pre/post hooks @@ -211,20 +211,20 @@ def base_url(self): return self.repo.config['base-url'] or u'' - + def from_controller(self): """return the id (string) of the controller issuing the request (no sense here, always return 'view') """ return 'view' - + def source_defs(self): return self.repo.source_defs() def describe(self, eid): """return a tuple (type, sourceuri, extid) for the entity with id """ return self.repo.type_and_source_from_eid(eid, self) - + # db-api like interface ################################################### def source_from_eid(self, eid): @@ -249,7 +249,7 @@ # need shared pool set self.set_pool() return csession - + def unsafe_execute(self, rql, kwargs=None, eid_key=None, build_descr=False, propagate=False): """like .execute but with security checking disabled (this method is @@ -266,7 +266,7 @@ def cursor(self): """return a rql cursor""" return self - + def execute(self, rql, kwargs=None, eid_key=None, build_descr=True, propagate=False): """db-api like method directly linked to the querier execute method @@ -276,7 +276,7 @@ """ rset = self._execute(self, rql, kwargs, eid_key, build_descr) return self.decorate_rset(rset, propagate) - + def commit(self, reset_pool=True): """commit the current session's transaction""" if self.pool is None: @@ -317,7 +317,7 @@ self._query_data.clear() if reset_pool: self.reset_pool() - + def rollback(self, reset_pool=True): """rollback the current session's transaction""" if self.pool is None: @@ -340,19 +340,19 @@ self._query_data.clear() if reset_pool: self.reset_pool() - + def close(self): """do not close pool on session close, since they are shared now""" self.rollback() - + # transaction data/operations management ################################## - + def add_query_data(self, key, value): self._query_data.setdefault(key, []).append(value) - + def set_query_data(self, key, value): self._query_data[key] = value - + def query_data(self, key, default=None, setdefault=False, pop=False): if setdefault: assert not pop @@ -361,7 +361,7 @@ return self._query_data.pop(key, default) else: return self._query_data.get(key, default) - + def add_operation(self, operation, index=None): """add an observer""" assert self.commit_state != 'commit' @@ -369,9 +369,9 @@ self.pending_operations.insert(index, operation) else: self.pending_operations.append(operation) - + # querier helpers ######################################################### - + def build_description(self, rqlst, args, result): """build a description for a given result""" if len(rqlst.children) == 1 and len(rqlst.children[0].solutions) == 1: @@ -385,7 +385,7 @@ def manual_build_descr(self, rqlst, args, result): """build a description for a given result by analysing each row - + XXX could probably be done more efficiently during execution of query """ # not so easy, looks for variable which changes from one solution @@ -410,7 +410,7 @@ if not todetermine: return [tuple(basedescription)] * len(result) return self._build_descr(result, basedescription, todetermine) - + def _build_descr(self, result, basedescription, todetermine): description = [] etype_from_eid = self.describe @@ -422,23 +422,23 @@ # None value inserted by an outer join, no type row_descr[index] = None continue - try: - if isfinal: - row_descr[index] = etype_from_pyobj(value) - else: + if isfinal: + row_descr[index] = etype_from_pyobj(value) + else: + try: row_descr[index] = etype_from_eid(value)[0] - except UnknownEid: - self.critical('wrong eid in repository, should check database') - row_descr[index] = row[index] = None + except UnknownEid: + self.critical('wrong eid %s in repository, should check database' % value) + row_descr[index] = row[index] = None description.append(tuple(row_descr)) return description - + class ChildSession(Session): """child (or internal) session are used to hijack the security system """ cnxtype = 'inmemory' - + def __init__(self, parent_session): self.id = None self.is_internal_session = False @@ -454,7 +454,7 @@ self._ = self.__ = parent_session._ # short cut to querier .execute method self._execute = self.repo.querier.execute - + @property def super_session(self): return self @@ -470,7 +470,7 @@ def set_commit_state(self, value): self.parent_session.set_commit_state(value) commit_state = property(get_commit_state, set_commit_state) - + @property def pool(self): return self.parent_session.pool @@ -480,11 +480,11 @@ @property def _query_data(self): return self.parent_session._query_data - + def set_pool(self): """the session need a pool to execute some queries""" self.parent_session.set_pool() - + def reset_pool(self): """the session has no longer using its pool, at least for some time """ @@ -493,19 +493,19 @@ def actual_session(self): """return the original parent session if any, else self""" return self.parent_session - + def commit(self, reset_pool=True): """commit the current session's transaction""" self.parent_session.commit(reset_pool) - + def rollback(self, reset_pool=True): """rollback the current session's transaction""" self.parent_session.rollback(reset_pool) - + def close(self): """do not close pool on session close, since they are shared now""" self.rollback() - + def user_data(self): """returns a dictionnary with this user's information""" return self.parent_session.user_data() @@ -513,14 +513,14 @@ class InternalSession(Session): """special session created internaly by the repository""" - + def __init__(self, repo, cnxprops=None): super(InternalSession, self).__init__(_IMANAGER, repo, cnxprops, _id='internal') self.cnxtype = 'inmemory' self.is_internal_session = True self.is_super_session = True - + @property def super_session(self): return self @@ -544,7 +544,7 @@ def owns(self, eid): return True - + def has_permission(self, pname, contexteid=None): return True