merge 3.19.3 into 3.20 branch
authorJulien Cristau <julien.cristau@logilab.fr>
Fri, 18 Jul 2014 17:35:25 +0200
changeset 9897 fa44db7da2dc
parent 9892 928732ec00dd (current diff)
parent 9896 4900a937838b (diff)
child 9898 70056633085c
merge 3.19.3 into 3.20 branch
migration.py
server/sources/datafeed.py
server/test/unittest_datafeed.py
web/application.py
web/data/cubicweb.css
web/data/cubicweb.edition.js
web/data/cubicweb.old.css
web/request.py
web/test/unittest_views_editforms.py
web/test/unittest_web.py
web/views/ajaxedit.py
web/views/autoform.py
--- a/.hgtags	Thu Jul 17 11:08:56 2014 +0200
+++ b/.hgtags	Fri Jul 18 17:35:25 2014 +0200
@@ -332,6 +332,9 @@
 ee413076752b3e606801ef55e48f7e7ccd1f7238 cubicweb-version-3.17.15
 ee413076752b3e606801ef55e48f7e7ccd1f7238 cubicweb-debian-version-3.17.15-1
 ee413076752b3e606801ef55e48f7e7ccd1f7238 cubicweb-centos-version-3.17.15-1
+a979d1594af6501a774fb32eb67cd32fea626655 cubicweb-version-3.17.16
+a979d1594af6501a774fb32eb67cd32fea626655 cubicweb-debian-version-3.17.16-1
+a979d1594af6501a774fb32eb67cd32fea626655 cubicweb-centos-version-3.17.16-1
 db37bf35a1474843ded0a537f9cb4838f4a78cda cubicweb-version-3.18.0
 db37bf35a1474843ded0a537f9cb4838f4a78cda cubicweb-debian-version-3.18.0-1
 db37bf35a1474843ded0a537f9cb4838f4a78cda cubicweb-centos-version-3.18.0-1
@@ -356,3 +359,9 @@
 1fe4bc4a8ac8831a379e9ebea08d75fbb6fc5c2a cubicweb-version-3.19.1
 1fe4bc4a8ac8831a379e9ebea08d75fbb6fc5c2a cubicweb-debian-version-3.19.1-1
 1fe4bc4a8ac8831a379e9ebea08d75fbb6fc5c2a cubicweb-centos-version-3.19.1-1
+8ac2202866e747444ce12778ff8789edd9c92eae cubicweb-version-3.19.2
+8ac2202866e747444ce12778ff8789edd9c92eae cubicweb-debian-version-3.19.2-1
+8ac2202866e747444ce12778ff8789edd9c92eae cubicweb-centos-version-3.19.2-1
+37f7c60f89f13dfcf326a4ea0a98ca20d959f7bd cubicweb-version-3.19.3
+37f7c60f89f13dfcf326a4ea0a98ca20d959f7bd cubicweb-debian-version-3.19.3-1
+37f7c60f89f13dfcf326a4ea0a98ca20d959f7bd cubicweb-centos-version-3.19.3-1
--- a/__pkginfo__.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/__pkginfo__.py	Fri Jul 18 17:35:25 2014 +0200
@@ -22,7 +22,7 @@
 
 modname = distname = "cubicweb"
 
-numversion = (3, 19, 1)
+numversion = (3, 19, 3)
 version = '.'.join(str(num) for num in numversion)
 
 description = "a repository of entities / relations for knowledge management"
@@ -44,8 +44,7 @@
     'rql': '>= 0.31.2',
     'yams': '>= 0.39.1',
     #gettext                    # for xgettext, msgcat, etc...
-    # web dependancies
-    'simplejson': '>= 2.0.9',
+    # web dependencies
     'lxml': '',
     'Twisted': '',
     # XXX graphviz
--- a/cubicweb.spec	Thu Jul 17 11:08:56 2014 +0200
+++ b/cubicweb.spec	Fri Jul 18 17:35:25 2014 +0200
@@ -7,7 +7,7 @@
 %endif
 
 Name:           cubicweb
-Version:        3.19.1
+Version:        3.19.3
 Release:        logilab.1%{?dist}
 Summary:        CubicWeb is a semantic web application framework
 Source0:        http://download.logilab.org/pub/cubicweb/cubicweb-%{version}.tar.gz
--- a/cwvreg.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/cwvreg.py	Fri Jul 18 17:35:25 2014 +0200
@@ -241,7 +241,7 @@
 
 class CWRegistry(Registry):
     def __init__(self, vreg):
-        super(CWRegistry, self).__init__(vreg.config)
+        super(CWRegistry, self).__init__(vreg.config.debugmode)
         self.vreg = vreg
 
     @property
--- a/dataimport.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/dataimport.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1114,7 +1114,6 @@
     def _handle_insert_entity_sql(self, session, sql, attrs):
         # We have to overwrite the source given in parameters
         # as here, we directly use the system source
-        attrs['source'] = 'system'
         attrs['asource'] = self.system_source.uri
         self._append_to_entities(sql, attrs)
 
@@ -1137,7 +1136,7 @@
             assert isinstance(extid, str)
             extid = b64encode(extid)
         attrs = {'type': entity.cw_etype, 'eid': entity.eid, 'extid': extid,
-                 'source': 'system', 'asource': source.uri}
+                 'asource': source.uri}
         self._handle_insert_entity_sql(session, self.sqlgen.insert('entities', attrs), attrs)
         # insert core relations: is, is_instance_of and cw_source
         try:
--- a/dbapi.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/dbapi.py	Fri Jul 18 17:35:25 2014 +0200
@@ -679,7 +679,16 @@
     @check_not_closed
     def entity_metas(self, eid):
         """return a tuple (type, sourceuri, extid) for the entity with id <eid>"""
-        return self._repo.entity_metas(self.sessionid, eid, **self._txid())
+        try:
+            return self._repo.entity_metas(self.sessionid, eid, **self._txid())
+        except AttributeError:
+            # talking to pre 3.19 repository
+            metas = self._repo.describe(self.sessionid, eid, **self._txid())
+            if len(metas) == 3: # even older backward compat
+                metas = list(metas)
+                metas.append(metas[1])
+            return dict(zip(('type', 'source', 'extid', 'asource'), metas))
+
 
     @deprecated('[3.19] use .entity_metas(eid) instead')
     @check_not_closed
--- a/debian/changelog	Thu Jul 17 11:08:56 2014 +0200
+++ b/debian/changelog	Fri Jul 18 17:35:25 2014 +0200
@@ -1,3 +1,15 @@
+cubicweb (3.19.3-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Julien Cristau <julien.cristau@logilab.fr>  Fri, 18 Jul 2014 16:16:32 +0200
+
+cubicweb (3.19.2-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Julien Cristau <julien.cristau@logilab.fr>  Thu, 03 Jul 2014 09:53:52 +0200
+
 cubicweb (3.19.1-1) unstable; urgency=low
 
   * new upstream release
@@ -46,6 +58,12 @@
 
  -- Julien Cristau <julien.cristau@logilab.fr>  Fri, 10 Jan 2014 17:14:18 +0100
 
+cubicweb (3.17.16-1) unstable; urgency=low
+
+  * new upstream value
+
+ -- Aurelien Campeas <aurelien.campeas@logilab.fr>  Mon, 07 Jul 2014 19:26:12 +0200
+
 cubicweb (3.17.15-1) unstable; urgency=low
 
   * new upstream release
--- a/debian/control	Thu Jul 17 11:08:56 2014 +0200
+++ b/debian/control	Fri Jul 18 17:35:25 2014 +0200
@@ -124,7 +124,6 @@
  ${misc:Depends},
  ${python:Depends},
  cubicweb-common (= ${source:Version}),
- python-simplejson (>= 2.0.9)
 Recommends:
  python-docutils (>= 0.6),
  python-vobject,
--- a/devtools/__init__.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/devtools/__init__.py	Fri Jul 18 17:35:25 2014 +0200
@@ -21,6 +21,7 @@
 
 import os
 import sys
+import errno
 import logging
 import shutil
 import pickle
@@ -277,8 +278,9 @@
                                               sourcefile='/path/to/sources')
 
           def test_something(self):
-              rset = self.execute('Any X WHERE X is CWUser')
-              self.view('foaf', rset)
+              with self.admin_access.web_request() as req:
+                  rset = req.execute('Any X WHERE X is CWUser')
+                  self.view('foaf', rset, req=req)
 
     """
     skip_db_create_and_restore = True
@@ -544,14 +546,29 @@
         super(PostgresTestDataBaseHandler, self).__init__(*args, **kwargs)
         datadir = join(self.config.apphome, 'pgdb')
         if not exists(datadir):
-            subprocess.check_call(['initdb', '-D', datadir, '-E', 'utf-8', '--locale=C'])
+            try:
+                subprocess.check_call(['initdb', '-D', datadir, '-E', 'utf-8', '--locale=C'])
+
+            except OSError, err:
+                if err.errno == errno.ENOENT:
+                    raise OSError('"initdb" could not be found. '
+                                  'You should add the postgresql bin folder to your PATH '
+                                  '(/usr/lib/postgresql/9.1/bin for example).')
+                raise
         port = self.system_source['db-port']
         directory = self.system_source['db-host']
         env = os.environ.copy()
         env['PGPORT'] = str(port)
         env['PGHOST'] = str(directory)
-        subprocess.check_call(['pg_ctl', 'start', '-w', '-D', datadir, '-o', '-h "" -k %s -p %s' % (directory, port)],
-                              env=env)
+        try:
+            subprocess.check_call(['pg_ctl', 'start', '-w', '-D', datadir, '-o', '-h "" -k %s -p %s' % (directory, port)],
+                                  env=env)
+        except OSError, err:
+            if err.errno == errno.ENOENT:
+                raise OSError('"pg_ctl" could not be found. '
+                              'You should add the postgresql bin folder to your PATH '
+                              '(/usr/lib/postgresql/9.1/bin for example).')
+            raise
         self.__CTL.add(datadir)
 
     @property
--- a/devtools/fill.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/devtools/fill.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,5 +1,5 @@
 # -*- coding: iso-8859-1 -*-
-# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -352,7 +352,7 @@
 
 
 
-def select(constraints, cursor, selectvar='O', objtype=None):
+def select(constraints, cnx, selectvar='O', objtype=None):
     """returns list of eids matching <constraints>
 
     <selectvar> should be either 'O' or 'S' to match schema definitions
@@ -361,7 +361,7 @@
         rql = 'Any %s WHERE %s' % (selectvar, constraints)
         if objtype:
             rql += ', %s is %s' % (selectvar, objtype)
-        rset = cursor.execute(rql)
+        rset = cnx.execute(rql)
     except Exception:
         print "could restrict eid_list with given constraints (%r)" % constraints
         return []
@@ -369,7 +369,7 @@
 
 
 
-def make_relations_queries(schema, edict, cursor, ignored_relations=(),
+def make_relations_queries(schema, edict, cnx, ignored_relations=(),
                            existingrels=None):
     """returns a list of generated RQL queries for relations
     :param schema: The instance schema
@@ -379,7 +379,7 @@
     :param ignored_relations: list of relations to ignore (i.e. don't try
                               to generate insert queries for these relations)
     """
-    gen = RelationsQueriesGenerator(schema, cursor, existingrels)
+    gen = RelationsQueriesGenerator(schema, cnx, existingrels)
     return gen.compute_queries(edict, ignored_relations)
 
 def composite_relation(rschema):
@@ -393,9 +393,9 @@
 
 class RelationsQueriesGenerator(object):
     rql_tmpl = 'SET S %s O WHERE S eid %%(subjeid)s, O eid %%(objeid)s'
-    def __init__(self, schema, cursor, existing=None):
+    def __init__(self, schema, cnx, existing=None):
         self.schema = schema
-        self.cursor = cursor
+        self.cnx = cnx
         self.existingrels = existing or {}
 
     def compute_queries(self, edict, ignored_relations):
@@ -457,7 +457,7 @@
             # restrict object eids if possible
             # XXX the attempt to restrict below in completely wrong
             # disabling it for now
-            objeids = select(restrictions, self.cursor, objtype=obj)
+            objeids = select(restrictions, self.cnx, objtype=obj)
         else:
             objeids = oedict.get(obj, frozenset())
         if subjcard in '?1' or objcard in '?1':
--- a/devtools/repotest.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/devtools/repotest.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -22,17 +22,12 @@
 
 __docformat__ = "restructuredtext en"
 
-from copy import deepcopy
 from pprint import pprint
 
-from logilab.common.decorators import clear_cache
 from logilab.common.testlib import SkipTest
 
-def tuplify(list):
-    for i in range(len(list)):
-        if type(list[i]) is not type(()):
-            list[i] = tuple(list[i])
-    return list
+def tuplify(mylist):
+    return [tuple(item) for item in mylist]
 
 def snippet_cmp(a, b):
     a = (a[0], [e.expression for e in a[1]])
@@ -40,17 +35,18 @@
     return cmp(a, b)
 
 def test_plan(self, rql, expected, kwargs=None):
-    plan = self._prepare_plan(rql, kwargs)
-    self.planner.build_plan(plan)
-    try:
-        self.assertEqual(len(plan.steps), len(expected),
-                          'expected %s steps, got %s' % (len(expected), len(plan.steps)))
-        # step order is important
-        for i, step in enumerate(plan.steps):
-            compare_steps(self, step.test_repr(), expected[i])
-    except AssertionError:
-        pprint([step.test_repr() for step in plan.steps])
-        raise
+    with self.session.new_cnx() as cnx:
+        plan = self._prepare_plan(cnx, rql, kwargs)
+        self.planner.build_plan(plan)
+        try:
+            self.assertEqual(len(plan.steps), len(expected),
+                              'expected %s steps, got %s' % (len(expected), len(plan.steps)))
+            # step order is important
+            for i, step in enumerate(plan.steps):
+                compare_steps(self, step.test_repr(), expected[i])
+        except AssertionError:
+            pprint([step.test_repr() for step in plan.steps])
+            raise
 
 def compare_steps(self, step, expected):
     try:
@@ -161,8 +157,9 @@
     def setUp(self):
         self.repo = FakeRepo(self.schema, config=FakeConfig(apphome=self.datadir))
         self.repo.system_source = mock_object(dbdriver=self.backend)
-        self.rqlhelper = RQLHelper(self.schema, special_relations={'eid': 'uid',
-                                                                   'has_text': 'fti'},
+        self.rqlhelper = RQLHelper(self.schema,
+                                   special_relations={'eid': 'uid',
+                                                      'has_text': 'fti'},
                                    backend=self.backend)
         self.qhelper = QuerierHelper(self.repo, self.schema)
         ExecutionPlan._check_permissions = _dummy_check_permissions
@@ -204,27 +201,22 @@
         self.ueid = self.session.user.eid
         assert self.ueid != -1
         self.repo._type_source_cache = {} # clear cache
-        self.cnxset = self.session.set_cnxset()
         self.maxeid = self.get_max_eid()
         do_monkey_patch()
         self._dumb_sessions = []
 
     def get_max_eid(self):
-        return self.session.execute('Any MAX(X)')[0][0]
+        with self.session.new_cnx() as cnx:
+            return cnx.execute('Any MAX(X)')[0][0]
+
     def cleanup(self):
-        self.session.set_cnxset()
-        self.session.execute('DELETE Any X WHERE X eid > %s' % self.maxeid)
+        with self.session.new_cnx() as cnx:
+            cnx.execute('DELETE Any X WHERE X eid > %s' % self.maxeid)
+            cnx.commit()
 
     def tearDown(self):
         undo_monkey_patch()
-        self.session.rollback()
         self.cleanup()
-        self.commit()
-        # properly close dumb sessions
-        for session in self._dumb_sessions:
-            session.rollback()
-            session.close()
-        self.repo._free_cnxset(self.cnxset)
         assert self.session.user.eid != -1
 
     def set_debug(self, debug):
@@ -239,7 +231,7 @@
         rqlhelper._analyser.uid_func_mapping = {}
         return rqlhelper
 
-    def _prepare_plan(self, rql, kwargs=None, simplify=True):
+    def _prepare_plan(self, cnx, rql, kwargs=None, simplify=True):
         rqlhelper = self._rqlhelper()
         rqlst = rqlhelper.parse(rql)
         rqlhelper.compute_solutions(rqlst, kwargs=kwargs)
@@ -247,10 +239,10 @@
             rqlhelper.simplify(rqlst)
         for select in rqlst.children:
             select.solutions.sort()
-        return self.o.plan_factory(rqlst, kwargs, self.session)
+        return self.o.plan_factory(rqlst, kwargs, cnx)
 
-    def _prepare(self, rql, kwargs=None):
-        plan = self._prepare_plan(rql, kwargs, simplify=False)
+    def _prepare(self, cnx, rql, kwargs=None):
+        plan = self._prepare_plan(cnx, rql, kwargs, simplify=False)
         plan.preprocess(plan.rqlst)
         rqlst = plan.rqlst.children[0]
         rqlst.solutions = remove_unused_solutions(rqlst, rqlst.solutions, {}, self.repo.schema)[0]
@@ -259,21 +251,20 @@
     def user_groups_session(self, *groups):
         """lightweight session using the current user with hi-jacked groups"""
         # use self.session.user.eid to get correct owned_by relation, unless explicit eid
-        u = self.repo._build_user(self.session, self.session.user.eid)
-        u._groups = set(groups)
-        s = Session(u, self.repo)
-        s._cnx.cnxset = self.cnxset
-        s._cnx.ctx_count = 1
-        # register session to ensure it gets closed
-        self._dumb_sessions.append(s)
-        return s
+        with self.session.new_cnx() as cnx:
+            u = self.repo._build_user(cnx, self.session.user.eid)
+            u._groups = set(groups)
+            s = Session(u, self.repo)
+            return s
 
-    def execute(self, rql, args=None, build_descr=True):
-        return self.o.execute(self.session, rql, args, build_descr)
-
-    def commit(self):
-        self.session.commit()
-        self.session.set_cnxset()
+    def qexecute(self, rql, args=None, build_descr=True):
+        with self.session.new_cnx() as cnx:
+            with cnx.ensure_cnx_set:
+                try:
+                    return self.o.execute(cnx, rql, args, build_descr)
+                finally:
+                    if rql.startswith(('INSERT', 'DELETE', 'SET')):
+                        cnx.commit()
 
 
 class BasePlannerTC(BaseQuerierTC):
@@ -282,31 +273,24 @@
         # XXX source_defs
         self.o = self.repo.querier
         self.session = self.repo._sessions.values()[0]
-        self.cnxset = self.session.set_cnxset()
         self.schema = self.o.schema
         self.system = self.repo.system_source
         do_monkey_patch()
-        self._dumb_sessions = [] # by hi-jacked parent setup
         self.repo.vreg.rqlhelper.backend = 'postgres' # so FTIRANK is considered
 
     def tearDown(self):
         undo_monkey_patch()
-        for session in self._dumb_sessions:
-            if session._cnx.cnxset is not None:
-                session._cnx.cnxset = None
-            session.close()
 
-    def _prepare_plan(self, rql, kwargs=None):
+    def _prepare_plan(self, cnx, rql, kwargs=None):
         rqlst = self.o.parse(rql, annotate=True)
-        self.o.solutions(self.session, rqlst, kwargs)
+        self.o.solutions(cnx, rqlst, kwargs)
         if rqlst.TYPE == 'select':
             self.repo.vreg.rqlhelper.annotate(rqlst)
             for select in rqlst.children:
                 select.solutions.sort()
         else:
             rqlst.solutions.sort()
-        with self.session.ensure_cnx_set:
-            return self.o.plan_factory(rqlst, kwargs, self.session)
+        return self.o.plan_factory(rqlst, kwargs, cnx)
 
 
 # monkey patch some methods to get predicatable results #######################
@@ -354,24 +338,6 @@
                                   _sort=lambda rels: sorted(rels, key=sort_key))
 
 
-def _merge_input_maps(*args, **kwargs):
-    return sorted(_orig_merge_input_maps(*args, **kwargs))
-
-def _choose_term(self, source, sourceterms):
-    # predictable order for test purpose
-    def get_key(x):
-        try:
-            # variable
-            return x.name
-        except AttributeError:
-            try:
-                # relation
-                return x.r_type
-            except AttributeError:
-                # const
-                return x.value
-    return _orig_choose_term(self, source, DumbOrderedDict2(sourceterms, get_key))
-
 def _ordered_iter_relations(stinfo):
     return sorted(_orig_iter_relations(stinfo), key=lambda x:x.r_type)
 
--- a/devtools/test/unittest_testlib.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/devtools/test/unittest_testlib.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -39,11 +39,13 @@
         class MyWebTest(CubicWebTC):
 
             def test_error_view(self):
-                self.request().create_entity('Bug', title=u"bt")
-                self.view('raising', self.execute('Bug B'), template=None)
+                with self.admin_access.web_request() as req:
+                    req.create_entity('Bug', title=u"bt")
+                    self.view('raising', req.execute('Bug B'), template=None, req=req)
 
             def test_correct_view(self):
-                self.view('primary', self.execute('CWUser U'), template=None)
+                with self.admin_access.web_request() as req:
+                    self.view('primary', req.execute('CWUser U'), template=None, req=req)
 
         tests = [MyWebTest('test_error_view'), MyWebTest('test_correct_view')]
         result = self.runner.run(TestSuite(tests))
@@ -98,6 +100,7 @@
 
 class HTMLPageInfoTC(TestCase):
     """test cases for PageInfo"""
+
     def setUp(self):
         parser = htmlparser.HTMLValidator()
         # disable cleanup that would remove doctype
@@ -113,7 +116,6 @@
         parser = htmlparser.DTDValidator()
         self.assertRaises(AssertionError, parser.parse_string, HTML_PAGE_ERROR)
 
-
     def test_has_title_no_level(self):
         """tests h? tags information"""
         self.assertEqual(self.page_info.has_title('Test'), True)
@@ -160,6 +162,7 @@
 
 
 class CWUtilitiesTC(CubicWebTC):
+
     def test_temporary_permissions_eschema(self):
         eschema = self.schema['CWUser']
         with self.temporary_permissions(CWUser={'read': ()}):
@@ -175,11 +178,13 @@
         self.assertTrue(rdef.permissions['read'], ())
 
     def test_temporary_appobjects_registered(self):
+
         class AnAppobject(object):
             __registries__ = ('hip',)
             __regid__ = 'hop'
             __select__ = yes()
             registered = None
+
             @classmethod
             def __registered__(cls, reg):
                 cls.registered = reg
@@ -190,10 +195,11 @@
         self.assertNotIn(AnAppobject, self.vreg['hip']['hop'])
 
     def test_login(self):
-        """Calling login should not break self.session hook control"""
-        self.hook_executed = False
-        babar = self.create_user(self.request(), 'babar')
-        self.commit()
+        """Calling login should not break hook control"""
+        with self.admin_access.repo_cnx() as cnx:
+            self.hook_executed = False
+            self.create_user(cnx, 'babar')
+            cnx.commit()
 
         from cubicweb.server import hook
         from cubicweb.predicates import is_instance
@@ -208,31 +214,31 @@
             def __call__(self):
                 self.test.hook_executed = True
 
-        self.login('babar')
-        with self.temporary_appobjects(MyHook):
-            with self.session.allow_all_hooks_but('test-hook'):
-                req = self.request()
-                prop = req.create_entity('CWProperty', pkey=u'ui.language', value=u'en')
-                self.commit()
-                self.assertFalse(self.hook_executed)
+        with self.new_access('babar').repo_cnx() as cnx:
+            with self.temporary_appobjects(MyHook):
+                with cnx.allow_all_hooks_but('test-hook'):
+                    prop = cnx.create_entity('CWProperty', pkey=u'ui.language', value=u'en')
+                    cnx.commit()
+                    self.assertFalse(self.hook_executed)
 
 
 class RepoAccessTC(CubicWebTC):
+
     def test_repo_connection(self):
         acc = self.new_access('admin')
-        with  acc.repo_cnx() as cnx:
+        with acc.repo_cnx() as cnx:
             rset = cnx.execute('Any X WHERE X is CWUser')
             self.assertTrue(rset)
 
     def test_client_connection(self):
         acc = self.new_access('admin')
-        with  acc.client_cnx() as cnx:
+        with acc.client_cnx() as cnx:
             rset = cnx.execute('Any X WHERE X is CWUser')
             self.assertTrue(rset)
 
     def test_web_request(self):
         acc = self.new_access('admin')
-        with  acc.web_request(elephant='babar') as req:
+        with acc.web_request(elephant='babar') as req:
             rset = req.execute('Any X WHERE X is CWUser')
             self.assertTrue(rset)
             self.assertEqual('babar', req.form['elephant'])
--- a/devtools/testlib.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/devtools/testlib.py	Fri Jul 18 17:35:25 2014 +0200
@@ -823,12 +823,13 @@
 
     def list_startup_views(self):
         """returns the list of startup views"""
-        req = self.request()
-        for view in self.vreg['views'].possible_views(req, None):
-            if view.category == 'startupview':
-                yield view.__regid__
-            else:
-                not_selected(self.vreg, view)
+        with self.admin_access.web_request() as req:
+            for view in self.vreg['views'].possible_views(req, None):
+                if view.category == 'startupview':
+                    yield view.__regid__
+                else:
+                    not_selected(self.vreg, view)
+
 
     # web ui testing utilities #################################################
 
@@ -842,6 +843,7 @@
         publisher.error_handler = raise_error_handler
         return publisher
 
+    @deprecated('[3.19] use the .remote_calling method')
     def remote_call(self, fname, *args):
         """remote json call simulation"""
         dump = json.dumps
@@ -850,6 +852,14 @@
         ctrl = self.vreg['controllers'].select('ajax', req)
         return ctrl.publish(), req
 
+    @contextmanager
+    def remote_calling(self, fname, *args):
+        """remote json call simulation"""
+        args = [json.dumps(arg) for arg in args]
+        with self.admin_access.web_request(fname=fname, pageid='123', arg=args) as req:
+            ctrl = self.vreg['controllers'].select('ajax', req)
+            yield ctrl.publish(), req
+
     def app_handle_request(self, req, path='view'):
         return self.app.core_handle(req, path)
 
@@ -1178,7 +1188,7 @@
 
 # XXX cleanup unprotected_entities & all mess
 
-def how_many_dict(schema, cursor, how_many, skip):
+def how_many_dict(schema, cnx, how_many, skip):
     """given a schema, compute how many entities by type we need to be able to
     satisfy relations cardinality.
 
@@ -1212,7 +1222,7 @@
     # step 1, compute a base number of each entity types: number of already
     # existing entities of this type + `how_many`
     for etype in unprotected_entities(schema, strict=True):
-        howmanydict[str(etype)] = cursor.execute('Any COUNT(X) WHERE X is %s' % etype)[0][0]
+        howmanydict[str(etype)] = cnx.execute('Any COUNT(X) WHERE X is %s' % etype)[0][0]
         if etype in unprotected:
             howmanydict[str(etype)] += how_many
     # step 2, augment nb entity per types to satisfy cardinality constraints,
@@ -1246,10 +1256,10 @@
     def to_test_etypes(self):
         return unprotected_entities(self.schema, strict=True)
 
-    def custom_populate(self, how_many, cursor):
+    def custom_populate(self, how_many, cnx):
         pass
 
-    def post_populate(self, cursor):
+    def post_populate(self, cnx):
         pass
 
 
@@ -1258,77 +1268,79 @@
         """this method populates the database with `how_many` entities
         of each possible type. It also inserts random relations between them
         """
-        with self.session.security_enabled(read=False, write=False):
-            self._auto_populate(how_many)
+        with self.admin_access.repo_cnx() as cnx:
+            with cnx.security_enabled(read=False, write=False):
+                self._auto_populate(cnx, how_many)
+                cnx.commit()
 
-    def _auto_populate(self, how_many):
-        cu = self.cursor()
-        self.custom_populate(how_many, cu)
+    def _auto_populate(self, cnx, how_many):
+        self.custom_populate(how_many, cnx)
         vreg = self.vreg
-        howmanydict = how_many_dict(self.schema, cu, how_many, self.no_auto_populate)
+        howmanydict = how_many_dict(self.schema, cnx, how_many, self.no_auto_populate)
         for etype in unprotected_entities(self.schema):
             if etype in self.no_auto_populate:
                 continue
             nb = howmanydict.get(etype, how_many)
             for rql, args in insert_entity_queries(etype, self.schema, vreg, nb):
-                cu.execute(rql, args)
+                cnx.execute(rql, args)
         edict = {}
         for etype in unprotected_entities(self.schema, strict=True):
-            rset = cu.execute('%s X' % etype)
+            rset = cnx.execute('%s X' % etype)
             edict[str(etype)] = set(row[0] for row in rset.rows)
         existingrels = {}
         ignored_relations = SYSTEM_RELATIONS | self.ignored_relations
         for rschema in self.schema.relations():
             if rschema.final or rschema in ignored_relations:
                 continue
-            rset = cu.execute('DISTINCT Any X,Y WHERE X %s Y' % rschema)
+            rset = cnx.execute('DISTINCT Any X,Y WHERE X %s Y' % rschema)
             existingrels.setdefault(rschema.type, set()).update((x, y) for x, y in rset)
-        q = make_relations_queries(self.schema, edict, cu, ignored_relations,
+        q = make_relations_queries(self.schema, edict, cnx, ignored_relations,
                                    existingrels=existingrels)
         for rql, args in q:
             try:
-                cu.execute(rql, args)
+                cnx.execute(rql, args)
             except ValidationError as ex:
                 # failed to satisfy some constraint
                 print 'error in automatic db population', ex
-                self.session.commit_state = None # reset uncommitable flag
-        self.post_populate(cu)
-        self.commit()
+                cnx.commit_state = None # reset uncommitable flag
+        self.post_populate(cnx)
 
     def iter_individual_rsets(self, etypes=None, limit=None):
         etypes = etypes or self.to_test_etypes()
-        for etype in etypes:
-            if limit:
-                rql = 'Any X LIMIT %s WHERE X is %s' % (limit, etype)
-            else:
-                rql = 'Any X WHERE X is %s' % etype
-            rset = self.execute(rql)
-            for row in xrange(len(rset)):
-                if limit and row > limit:
-                    break
-                # XXX iirk
-                rset2 = rset.limit(limit=1, offset=row)
-                yield rset2
+        with self.admin_access.web_request() as req:
+            for etype in etypes:
+                if limit:
+                    rql = 'Any X LIMIT %s WHERE X is %s' % (limit, etype)
+                else:
+                    rql = 'Any X WHERE X is %s' % etype
+                rset = req.execute(rql)
+                for row in xrange(len(rset)):
+                    if limit and row > limit:
+                        break
+                    # XXX iirk
+                    rset2 = rset.limit(limit=1, offset=row)
+                    yield rset2
 
     def iter_automatic_rsets(self, limit=10):
         """generates basic resultsets for each entity type"""
         etypes = self.to_test_etypes()
         if not etypes:
             return
-        for etype in etypes:
-            yield self.execute('Any X LIMIT %s WHERE X is %s' % (limit, etype))
-        etype1 = etypes.pop()
-        try:
-            etype2 = etypes.pop()
-        except KeyError:
-            etype2 = etype1
-        # test a mixed query (DISTINCT/GROUP to avoid getting duplicate
-        # X which make muledit view failing for instance (html validation fails
-        # because of some duplicate "id" attributes)
-        yield self.execute('DISTINCT Any X, MAX(Y) GROUPBY X WHERE X is %s, Y is %s' % (etype1, etype2))
-        # test some application-specific queries if defined
-        for rql in self.application_rql:
-            yield self.execute(rql)
+        with self.admin_access.web_request() as req:
+            for etype in etypes:
+                yield req.execute('Any X LIMIT %s WHERE X is %s' % (limit, etype))
+            etype1 = etypes.pop()
+            try:
+                etype2 = etypes.pop()
+            except KeyError:
+                etype2 = etype1
+            # test a mixed query (DISTINCT/GROUP to avoid getting duplicate
+            # X which make muledit view failing for instance (html validation fails
+            # because of some duplicate "id" attributes)
+            yield req.execute('DISTINCT Any X, MAX(Y) GROUPBY X WHERE X is %s, Y is %s' % (etype1, etype2))
+            # test some application-specific queries if defined
+            for rql in self.application_rql:
+                yield req.execute(rql)
 
     def _test_everything_for(self, rset):
         """this method tries to find everything that can be tested
@@ -1390,8 +1402,8 @@
     ## startup views
     def test_startup_views(self):
         for vid in self.list_startup_views():
-            req = self.request()
-            yield self.view, vid, None, req
+            with self.admin_access.web_request() as req:
+                yield self.view, vid, None, req
 
 
 # registry instrumentization ###################################################
--- a/doc/book/en/annexes/rql/language.rst	Thu Jul 17 11:08:56 2014 +0200
+++ b/doc/book/en/annexes/rql/language.rst	Fri Jul 18 17:35:25 2014 +0200
@@ -350,9 +350,10 @@
   matching state of or tagged by the expected tag,
 
 * the later will retrieve all versions, state and tags (cartesian product!),
-  compute join and then exclude each row which are in the matching state of or
-  tagged by the expected tag. This implies that : you won't get any result if the
-  in_state or tag
+  compute join and then exclude each row which are in the matching state or
+  tagged by the expected tag. This implies that you won't get any result if the
+  in_state or tag tables are empty (ie there is no such relation in the
+  application). This is usually NOT what you want.
 
 Another common case where you may want to use ``EXISTS`` is when you
 find yourself using ``DISTINCT`` at the beginning of your query to
@@ -562,19 +563,19 @@
 
 Aggregate functions
 ```````````````````
-+--------------------+----------------------------------------------------------+
-| :func:`COUNT`      | return the number of rows                                |
-+--------------------+----------------------------------------------------------+
-| :func:`MIN`        | return the minimum value                                 |
-+--------------------+----------------------------------------------------------+
-| :func:`MAX`        | return the maximum value                                 |
-+--------------------+----------------------------------------------------------+
-| :func:`AVG`        | return the average value                                 |
-+--------------------+----------------------------------------------------------+
-| :func:`SUM`        | return the sum of values                                 |
-+--------------------+----------------------------------------------------------+
-| :func:`COMMA_JOIN` | return each value separated by a comma (for string only) |
-+--------------------+----------------------------------------------------------+
++------------------------+----------------------------------------------------------+
+| ``COUNT(Any)``         | return the number of rows                                |
++------------------------+----------------------------------------------------------+
+| ``MIN(Any)``           | return the minimum value                                 |
++------------------------+----------------------------------------------------------+
+| ``MAX(Any)``           | return the maximum value                                 |
++------------------------+----------------------------------------------------------+
+| ``AVG(Any)``           | return the average value                                 |
++------------------------+----------------------------------------------------------+
+| ``SUM(Any)``           | return the sum of values                                 |
++------------------------+----------------------------------------------------------+
+| ``COMMA_JOIN(String)`` | return each value separated by a comma (for string only) |
++------------------------+----------------------------------------------------------+
 
 All aggregate functions above take a single argument. Take care some aggregate
 functions (e.g. ``MAX``, ``MIN``) may return `None` if there is no
@@ -585,67 +586,67 @@
 String transformation functions
 ```````````````````````````````
 
-+---------------------------------------------------+-----------------------------------------------------------------+
-| :func:`UPPER(String)`                             | upper case the string                                           |
-+---------------------------------------------------+-----------------------------------------------------------------+
-| :func:`LOWER(String)`                             | lower case the string                                           |
-+---------------------------------------------------+-----------------------------------------------------------------+
-| :func:`LENGTH(String)`                            | return the length of the string                                 |
-+---------------------------------------------------+-----------------------------------------------------------------+
-| :func:`SUBSTRING(String, start, length)`          | extract from the string a string starting at given index and of |
-|                                                   | given length                                                    |
-+---------------------------------------------------+-----------------------------------------------------------------+
-| :func:`LIMIT_SIZE(String, max size)`              | if the length of the string is greater than given max size,     |
-|                                                   | strip it and add ellipsis ("..."). The resulting string will    |
-|                                                   | hence have max size + 3 characters                              |
-+---------------------------------------------------+-----------------------------------------------------------------+
-| :func:`TEXT_LIMIT_SIZE(String, format, max size)` | similar to the above, but allow to specify the MIME type of the |
-|                                                   | text contained by the string. Supported formats are text/html,  |
-|                                                   | text/xhtml and text/xml. All others will be considered as plain |
-|                                                   | text. For non plain text format, sgml tags will be first removed|
-|                                                   | before limiting the string.                                     |
-+---------------------------------------------------+-----------------------------------------------------------------+
++-----------------------------------------------+-----------------------------------------------------------------+
+| ``UPPER(String)``                             | upper case the string                                           |
++-----------------------------------------------+-----------------------------------------------------------------+
+| ``LOWER(String)``                             | lower case the string                                           |
++-----------------------------------------------+-----------------------------------------------------------------+
+| ``LENGTH(String)``                            | return the length of the string                                 |
++-----------------------------------------------+-----------------------------------------------------------------+
+| ``SUBSTRING(String, start, length)``          | extract from the string a string starting at given index and of |
+|                                               | given length                                                    |
++-----------------------------------------------+-----------------------------------------------------------------+
+| ``LIMIT_SIZE(String, max size)``              | if the length of the string is greater than given max size,     |
+|                                               | strip it and add ellipsis ("..."). The resulting string will    |
+|                                               | hence have max size + 3 characters                              |
++-----------------------------------------------+-----------------------------------------------------------------+
+| ``TEXT_LIMIT_SIZE(String, format, max size)`` | similar to the above, but allow to specify the MIME type of the |
+|                                               | text contained by the string. Supported formats are text/html,  |
+|                                               | text/xhtml and text/xml. All others will be considered as plain |
+|                                               | text. For non plain text format, sgml tags will be first removed|
+|                                               | before limiting the string.                                     |
++-----------------------------------------------+-----------------------------------------------------------------+
 
 .. _RQLDateFunctions:
 
 Date extraction functions
 `````````````````````````
 
-+--------------------------+----------------------------------------+
-| :func:`YEAR(Date)`       | return the year of a date or datetime  |
-+--------------------------+----------------------------------------+
-| :func:`MONTH(Date)`      | return the month of a date or datetime |
-+--------------------------+----------------------------------------+
-| :func:`DAY(Date)`        | return the day of a date or datetime   |
-+--------------------------+----------------------------------------+
-| :func:`HOUR(Datetime)`   | return the hours of a datetime         |
-+--------------------------+----------------------------------------+
-| :func:`MINUTE(Datetime)` | return the minutes of a datetime       |
-+--------------------------+----------------------------------------+
-| :func:`SECOND(Datetime)` | return the seconds of a datetime       |
-+--------------------------+----------------------------------------+
-| :func:`WEEKDAY(Date)`    | return the day of week of a date or    |
-|                          | datetime.  Sunday == 1, Saturday == 7. |
-+--------------------------+----------------------------------------+
++----------------------+----------------------------------------+
+| ``YEAR(Date)``       | return the year of a date or datetime  |
++----------------------+----------------------------------------+
+| ``MONTH(Date)``      | return the month of a date or datetime |
++----------------------+----------------------------------------+
+| ``DAY(Date)``        | return the day of a date or datetime   |
++----------------------+----------------------------------------+
+| ``HOUR(Datetime)``   | return the hours of a datetime         |
++----------------------+----------------------------------------+
+| ``MINUTE(Datetime)`` | return the minutes of a datetime       |
++----------------------+----------------------------------------+
+| ``SECOND(Datetime)`` | return the seconds of a datetime       |
++----------------------+----------------------------------------+
+| ``WEEKDAY(Date)``    | return the day of week of a date or    |
+|                      | datetime.  Sunday == 1, Saturday == 7. |
++----------------------+----------------------------------------+
 
 .. _RQLOtherFunctions:
 
 Other functions
 ```````````````
-+-----------------------+--------------------------------------------------------------------+
-| :func:`ABS(num)`      |  return the absolute value of a number                             |
-+-----------------------+--------------------------------------------------------------------+
-| :func:`RANDOM()`      | return a pseudo-random value from 0.0 to 1.0                       |
-+-----------------------+--------------------------------------------------------------------+
-| :func:`FSPATH(X)`     | expect X to be an attribute whose value is stored in a             |
-|                       | :class:`BFSStorage` and return its path on the file system         |
-+-----------------------+--------------------------------------------------------------------+
-| :func:`FTIRANK(X)`    | expect X to be an entity used in a has_text relation, and return a |
-|                       | number corresponding to the rank order of each resulting entity    |
-+-----------------------+--------------------------------------------------------------------+
-| :func:`CAST(Type, X)` | expect X to be an attribute and return it casted into the given    |
-|                       | final type                                                         |
-+-----------------------+--------------------------------------------------------------------+
++-------------------+--------------------------------------------------------------------+
+| ``ABS(num)``      |  return the absolute value of a number                             |
++-------------------+--------------------------------------------------------------------+
+| ``RANDOM()``      | return a pseudo-random value from 0.0 to 1.0                       |
++-------------------+--------------------------------------------------------------------+
+| ``FSPATH(X)``     | expect X to be an attribute whose value is stored in a             |
+|                   | :class:`BFSStorage` and return its path on the file system         |
++-------------------+--------------------------------------------------------------------+
+| ``FTIRANK(X)``    | expect X to be an entity used in a has_text relation, and return a |
+|                   | number corresponding to the rank order of each resulting entity    |
++-------------------+--------------------------------------------------------------------+
+| ``CAST(Type, X)`` | expect X to be an attribute and return it casted into the given    |
+|                   | final type                                                         |
++-------------------+--------------------------------------------------------------------+
 
 
 .. _RQLExamples:
@@ -657,7 +658,7 @@
 
   .. sourcecode:: sql
 
-        Any WHERE X eid 53
+        Any X WHERE X eid 53
 
 - *Search material such as comics, owned by syt and available*
 
@@ -686,7 +687,7 @@
 
   .. sourcecode:: sql
 
-        Any P WHERE P is Person, (P interested_by T, T name 'training') OR
+        Any P WHERE P is Person, EXISTS(P interested_by T, T name 'training') OR
                     (P city 'Paris')
 
 - *The surname and firstname of all people*
--- a/doc/book/en/devrepo/testing.rst	Thu Jul 17 11:08:56 2014 +0200
+++ b/doc/book/en/devrepo/testing.rst	Fri Jul 18 17:35:25 2014 +0200
@@ -25,8 +25,8 @@
 http://docs.python.org/library/sqlite3.html) as a backend.
 
 The database is stored in the mycube/test/tmpdb,
-mycube/test/tmpdb-template files. If it does not (yet) exists, it will
-be built automatically when the test suit starts.
+mycube/test/tmpdb-template files. If it does not (yet) exist, it will
+be built automatically when the test suite starts.
 
 .. warning::
 
@@ -34,8 +34,8 @@
   one must delete these two files. Changes concerned only with entity
   or relation type properties (constraints, cardinalities,
   permissions) and generally dealt with using the
-  `sync_schema_props_perms()` fonction of the migration environment
-  need not a database regeneration step.
+  `sync_schema_props_perms()` function of the migration environment do
+  not need a database regeneration step.
 
 .. _hook_test:
 
@@ -53,56 +53,58 @@
     class ClassificationHooksTC(CubicWebTC):
 
         def setup_database(self):
-            req = self.request()
-            group_etype = req.find_one_entity('CWEType', name='CWGroup')
-            c1 = req.create_entity('Classification', name=u'classif1',
-                                   classifies=group_etype)
-            user_etype = req.find_one_entity('CWEType', name='CWUser')
-            c2 = req.create_entity('Classification', name=u'classif2',
-                                   classifies=user_etype)
-            self.kw1 = req.create_entity('Keyword', name=u'kwgroup', included_in=c1)
-            self.kw2 = req.create_entity('Keyword', name=u'kwuser', included_in=c2)
+            with self.admin_access.repo_cnx() as cnx:
+                group_etype = cnx.find('CWEType', name='CWGroup').one()
+                c1 = cnx.create_entity('Classification', name=u'classif1',
+                                       classifies=group_etype)
+                user_etype = cnx.find('CWEType', name='CWUser').one()
+                c2 = cnx.create_entity('Classification', name=u'classif2',
+                                       classifies=user_etype)
+                self.kw1eid = cnx.create_entity('Keyword', name=u'kwgroup', included_in=c1).eid
+                cnx.commit()
 
         def test_cannot_create_cycles(self):
-            # direct obvious cycle
-            self.assertRaises(ValidationError, self.kw1.cw_set,
-                              subkeyword_of=self.kw1)
-            # testing indirect cycles
-            kw3 = self.execute('INSERT Keyword SK: SK name "kwgroup2", SK included_in C, '
-                               'SK subkeyword_of K WHERE C name "classif1", K eid %s'
-                               % self.kw1.eid).get_entity(0,0)
-            self.kw1.cw_set(subkeyword_of=kw3)
-            self.assertRaises(ValidationError, self.commit)
+            with self.admin_access.repo_cnx() as cnx:
+                kw1 = cnx.entity_from_eid(self.kw1eid)
+                # direct obvious cycle
+                with self.assertRaises(ValidationError):
+                    kw1.cw_set(subkeyword_of=kw1)
+                cnx.rollback()
+                # testing indirect cycles
+                kw3 = cnx.execute('INSERT Keyword SK: SK name "kwgroup2", SK included_in C, '
+                                  'SK subkeyword_of K WHERE C name "classif1", K eid %(k)s'
+                                  {'k': kw1}).get_entity(0,0)
+                kw3.cw_set(reverse_subkeyword_of=kw1)
+                self.assertRaises(ValidationError, cnx.commit)
 
 The test class defines a :meth:`setup_database` method which populates the
 database with initial data. Each test of the class runs with this
-pre-populated database. A commit is done automatically after the
-:meth:`setup_database` call. You don't have to call it explicitely.
+pre-populated database.
 
-The test case itself checks that an Operation does it job of
+The test case itself checks that an Operation does its job of
 preventing cycles amongst Keyword entities.
 
-`create_entity` is a useful method, which easily allows to create an
-entity. You can link this entity to others entities, by specifying as
-argument, the relation name, and the entity to link, as value. In the
-above example, the `Classification` entity is linked to a `CWEtype`
-via the relation `classifies`. Conversely, if you are creating a
-`CWEtype` entity, you can link it to a `Classification` entity, by
-adding `reverse_classifies` as argument.
+The `create_entity` method of connection (or request) objects allows
+to create an entity. You can link this entity to other entities, by
+specifying as argument, the relation name, and the entity to link, as
+value. In the above example, the `Classification` entity is linked to
+a `CWEtype` via the relation `classifies`. Conversely, if you are
+creating a `CWEtype` entity, you can link it to a `Classification`
+entity, by adding `reverse_classifies` as argument.
 
 .. note::
 
-   :meth:`commit` method is not called automatically in test_XXX
-   methods. You have to call it explicitely if needed (notably to test
-   operations). It is a good practice to call :meth:`clear_all_caches`
-   on entities after a commit to avoid request cache effects.
+   the :meth:`commit` method is not called automatically. You have to
+   call it explicitly if needed (notably to test operations). It is a
+   good practice to regenerate entities with :meth:`entity_from_eid`
+   after a commit to avoid request cache effects.
 
 You can see an example of security tests in the
 :ref:`adv_tuto_security`.
 
 It is possible to have these tests run continuously using `apycot`_.
 
-.. _apycot: http://www.logilab.org/project/apycot
+.. _apycot: http://www.cubicweb.org/project/apycot
 
 .. _securitytest:
 
@@ -113,66 +115,50 @@
 support multiple connections at a time, you must be careful when
 simulating security, changing users.
 
-By default, tests run with a user with admin privileges. This
-user/connection must never be closed.
+By default, tests run with a user with admin privileges. Connections
+using these credentials are accessible through the `admin_access` object
+of the test classes.
 
-Before a self.login, one has to release the connection pool in use
-with a self.commit, self.rollback or self.close.
-
-The `login` method returns a connection object that can be used as a
+The `repo_cnx()` method returns a connection object that can be used as a
 context manager:
 
 .. sourcecode:: python
 
-   with self.login('user1') as user:
-       req = user.req
-       req.execute(...)
-
-On exit of the context manager, either a commit or rollback is issued,
-which releases the connection.
-
-When one is logged in as a normal user and wants to switch back to the
-admin user without committing, one has to use
-self.restore_connection().
-
-Usage with restore_connection:
-
-.. sourcecode:: python
+   # admin_access is a pre-cooked session wrapping object
+   # it is built with:
+   # self.admin_access = self.new_access('admin')
+   with self.admin_access.repo_cnx() as cnx:
+       cnx.execute(...)
+       self.create_user(cnx, login='user1')
+       cnx.commit()
 
-    # execute using default admin connection
-    self.execute(...)
-    # I want to login with another user, ensure to free admin connection pool
-    # (could have used rollback but not close here
-    # we should never close defaut admin connection)
-    self.commit()
-    cnx = self.login('user')
-    # execute using user connection
-    self.execute(...)
-    # I want to login with another user or with admin user
-    self.commit();  cnx.close()
-    # restore admin connection, never use cnx = self.login('admin'), it will return
-    # the default admin connection and one may be tempted to close it
-    self.restore_connection()
+   user1access = self.new_access('user1')
+   with user1access.web_request() as req:
+       req.execute(...)
+       req.cnx.commit()
+
+On exit of the context manager, a rollback is issued, which releases
+the connection. Don't forget to issue the `cnx.commit()` calls!
 
 .. warning::
 
-   Do not use the references kept to the entities created with a
-   connection from another !
+   Do not use references kept to the entities created with a
+   connection from another one!
 
 Email notifications tests
 `````````````````````````
 
-When running tests potentially generated e-mails are not really sent
-but is found in the list `MAILBOX` of module
+When running tests, potentially generated e-mails are not really sent
+but are found in the list `MAILBOX` of module
 :mod:`cubicweb.devtools.testlib`.
 
 You can test your notifications by analyzing the contents of this list, which
 contains objects with two attributes:
 
 * `recipients`, the list of recipients
-* `msg`, object email.Message
+* `msg`, email.Message object
 
-Let us look at simple example from the ``blog`` cube.
+Let us look at a simple example from the ``blog`` cube.
 
 .. sourcecode:: python
 
@@ -182,28 +168,28 @@
         """test blog specific behaviours"""
 
         def test_notifications(self):
-            req = self.request()
-            cubicweb_blog = req.create_entity('Blog', title=u'cubicweb',
-                                description=u'cubicweb is beautiful')
-            blog_entry_1 = req.create_entity('BlogEntry', title=u'hop',
-                                             content=u'cubicweb hop')
-            blog_entry_1.cw_set(entry_of=cubicweb_blog)
-            blog_entry_2 = req.create_entity('BlogEntry', title=u'yes',
-                                             content=u'cubicweb yes')
-            blog_entry_2.cw_set(entry_of=cubicweb_blog)
-            self.assertEqual(len(MAILBOX), 0)
-            self.commit()
-            self.assertEqual(len(MAILBOX), 2)
-            mail = MAILBOX[0]
-            self.assertEqual(mail.subject, '[data] hop')
-            mail = MAILBOX[1]
-            self.assertEqual(mail.subject, '[data] yes')
+            with self.admin_access.web_request() as req:
+                cubicweb_blog = req.create_entity('Blog', title=u'cubicweb',
+                                    description=u'cubicweb is beautiful')
+                blog_entry_1 = req.create_entity('BlogEntry', title=u'hop',
+                                                 content=u'cubicweb hop')
+                blog_entry_1.cw_set(entry_of=cubicweb_blog)
+                blog_entry_2 = req.create_entity('BlogEntry', title=u'yes',
+                                                 content=u'cubicweb yes')
+                blog_entry_2.cw_set(entry_of=cubicweb_blog)
+                self.assertEqual(len(MAILBOX), 0)
+                req.cnx.commit()
+                self.assertEqual(len(MAILBOX), 2)
+                mail = MAILBOX[0]
+                self.assertEqual(mail.subject, '[data] hop')
+                mail = MAILBOX[1]
+                self.assertEqual(mail.subject, '[data] yes')
 
 Visible actions tests
 `````````````````````
 
 It is easy to write unit tests to test actions which are visible to
-user or to a category of users. Let's take an example in the
+a user or to a category of users. Let's take an example in the
 `conference cube`_.
 
 .. _`conference cube`: http://www.cubicweb.org/project/cubicweb-conference
@@ -212,34 +198,35 @@
     class ConferenceActionsTC(CubicWebTC):
 
         def setup_database(self):
-            self.conf = self.create_entity('Conference',
-                                           title=u'my conf',
-                                           url_id=u'conf',
-                                           start_on=date(2010, 1, 27),
-                                           end_on = date(2010, 1, 29),
-                                           call_open=True,
-                                           reverse_is_chair_at=chair,
-                                           reverse_is_reviewer_at=reviewer)
+            with self.admin_access.repo_cnx() as cnx:
+                self.confeid = cnx.create_entity('Conference',
+                                                 title=u'my conf',
+                                                 url_id=u'conf',
+                                                 start_on=date(2010, 1, 27),
+                                                 end_on = date(2010, 1, 29),
+                                                 call_open=True,
+                                                 reverse_is_chair_at=chair,
+                                                 reverse_is_reviewer_at=reviewer).eid
 
         def test_admin(self):
-            req = self.request()
-            rset = req.find_entities('Conference')
-            self.assertListEqual(self.pactions(req, rset),
-                                  [('workflow', workflow.WorkflowActions),
-                                   ('edit', confactions.ModifyAction),
-                                   ('managepermission', actions.ManagePermissionsAction),
-                                   ('addrelated', actions.AddRelatedActions),
-                                   ('delete', actions.DeleteAction),
-                                   ('generate_badge_action', badges.GenerateBadgeAction),
-                                   ('addtalkinconf', confactions.AddTalkInConferenceAction)
-                                   ])
-            self.assertListEqual(self.action_submenu(req, rset, 'addrelated'),
-                                  [(u'add Track in_conf Conference object',
-                                    u'http://testing.fr/cubicweb/add/Track'
-                                    u'?__linkto=in_conf%%3A%(conf)s%%3Asubject&'
-                                    u'__redirectpath=conference%%2Fconf&'
-                                    u'__redirectvid=' % {'conf': self.conf.eid}),
-                                   ])
+            with self.admin_access.web_request() as req:
+                rset = req.find('Conference').one()
+                self.assertListEqual(self.pactions(req, rset),
+                                      [('workflow', workflow.WorkflowActions),
+                                       ('edit', confactions.ModifyAction),
+                                       ('managepermission', actions.ManagePermissionsAction),
+                                       ('addrelated', actions.AddRelatedActions),
+                                       ('delete', actions.DeleteAction),
+                                       ('generate_badge_action', badges.GenerateBadgeAction),
+                                       ('addtalkinconf', confactions.AddTalkInConferenceAction)
+                                       ])
+                self.assertListEqual(self.action_submenu(req, rset, 'addrelated'),
+                                      [(u'add Track in_conf Conference object',
+                                        u'http://testing.fr/cubicweb/add/Track'
+                                        u'?__linkto=in_conf%%3A%(conf)s%%3Asubject&'
+                                        u'__redirectpath=conference%%2Fconf&'
+                                        u'__redirectvid=' % {'conf': self.confeid}),
+                                       ])
 
 You just have to execute a rql query corresponding to the view you want to test,
 and to compare the result of
@@ -247,7 +234,7 @@
 that must be visible in the interface. This is a list of tuples. The first
 element is the action's `__regid__`, the second the action's class.
 
-To test actions in submenu, you just have to test the result of
+To test actions in a submenu, you just have to test the result of
 :meth:`~cubicweb.devtools.testlib.CubicWebTC.action_submenu` method. The last
 parameter of the method is the action's category. The result is a list of
 tuples. The first element is the action's title, and the second element the
@@ -290,23 +277,27 @@
 Cache heavy database setup
 -------------------------------
 
-Some tests suite require a complex setup of the database that takes seconds (or
-event minutes) to complete. Doing the whole setup for all individual tests make
-the whole run very slow. The ``CubicWebTC`` class offer a simple way to prepare
-specific database once for multiple tests. The `test_db_id` class attribute of
-your ``CubicWebTC`` must be set a unique identifier and the
-:meth:`pre_setup_database` class method build the cached content. As the
-:meth:`pre_setup_database` method is not grantee to be called, you must not set
-any class attribut to be used during test there.  Databases for each `test_db_id`
-are automatically created if not already in cache.  Clearing the cache is up to
-the user. Cache files are found in the :file:`data/database` subdirectory of your
-test directory.
+Some test suites require a complex setup of the database that takes
+seconds (or even minutes) to complete. Doing the whole setup for each
+individual test makes the whole run very slow. The ``CubicWebTC``
+class offer a simple way to prepare a specific database once for
+multiple tests. The `test_db_id` class attribute of your
+``CubicWebTC`` subclass must be set to a unique identifier and the
+:meth:`pre_setup_database` class method must build the cached content. As
+the :meth:`pre_setup_database` method is not garanteed to be called
+every time a test method is run, you must not set any class attribute
+to be used during test *there*. Databases for each `test_db_id` are
+automatically created if not already in cache. Clearing the cache is
+up to the user. Cache files are found in the :file:`data/database`
+subdirectory of your test directory.
 
 .. warning::
 
-  Take care to always have the same :meth:`pre_setup_database` function for all
-  call with a given `test_db_id` otherwise you test will have unpredictable
-  result given the first encountered one.
+  Take care to always have the same :meth:`pre_setup_database`
+  function for all classes with a given `test_db_id` otherwise your
+  tests will have unpredictable results depending on the first
+  encountered one.
+
 
 Testing on a real-life database
 -------------------------------
@@ -332,10 +323,10 @@
                                             sourcefile='/path/to/realdb_sources')
 
         def test_blog_rss(self):
-            req = self.request()
+            with self.admin_access.web_request() as req:
             rset = req.execute('Any B ORDERBY D DESC WHERE B is BlogEntry, '
-                'B created_by U, U login "logilab", B creation_date D')
-            self.view('rss', rset)
+                               'B created_by U, U login "logilab", B creation_date D')
+            self.view('rss', rset, req=req)
 
 
 Testing with other cubes
@@ -351,7 +342,7 @@
 The format is:
 
 * possibly several empy lines or lines starting with ``#`` (comment lines)
-* one line containing a coma separated list of cube names.
+* one line containing a comma-separated list of cube names.
 
 It is also possible to add a ``schema.py`` file in
 ``mycube/test/data``, which will be used by the testing framework,
@@ -362,12 +353,12 @@
 --------------------
 
 CubicWeb provides some literate programming capabilities. The :ref:`cubicweb-ctl`
-`shell` command accepts differents format files. If your file ends with `.txt`
-or `.rst`, the file will be parsed by :mod:`doctest.testfile` with CubicWeb
+`shell` command accepts different file formats. If your file ends with `.txt`
+or `.rst`, the file will be parsed by :mod:`doctest.testfile` with CubicWeb's
 :ref:`migration` API enabled in it.
 
-Create a `scenario.txt` file into `test/` directory and fill with some content.
-Please refer the :mod:`doctest.testfile` `documentation`_.
+Create a `scenario.txt` file in the `test/` directory and fill with some content.
+Refer to the :mod:`doctest.testfile` `documentation`_.
 
 .. _documentation: http://docs.python.org/library/doctest.html
 
@@ -404,7 +395,7 @@
 
 Passing paramaters
 ``````````````````
-Using extra arguments to parametrize your scenario is possible by prepend them
+Using extra arguments to parametrize your scenario is possible by prepending them
 by double dashes.
 
 Please refer to the `cubicweb-ctl shell --help` usage.
@@ -431,7 +422,7 @@
   discover them automatically)
 * launch `pytest unittest_foo.py` to execute one test file
 * launch `pytest unittest_foo.py bar` to execute all test methods and
-  all test cases whose name contain `bar`
+  all test cases whose name contains `bar`
 
 Additionally, the `-x` option tells pytest to exit at the first error
 or failure. The `-i` option tells pytest to drop into pdb whenever an
@@ -460,7 +451,6 @@
 What you need to know about request and session
 -----------------------------------------------
 
-
 .. image:: ../images/request_session.png
 
 First, remember to think that some code run on a client side, some
@@ -474,9 +464,14 @@
 The client interacts with the repository through a repoapi connection.
 
 
+.. note::
+
+   These distinctions are going to disappear in cubicweb 3.21 (if not
+   before).
+
 A repoapi connection is tied to a session in the repository. The connection and
-request objects are unaccessible from repository code / the session object is
-unaccessible from client code (theoretically at least).
+request objects are inaccessible from repository code / the session object is
+inaccessible from client code (theoretically at least).
 
 The web interface provides a request class.  That `request` object provides
 access to all cubicweb resources, eg:
@@ -492,7 +487,7 @@
 
 
 A `session` provides an api similar to a request regarding RQL execution and
-access to global resources (registry and all), but also have the following
+access to global resources (registry and all), but also has the following
 responsibilities:
 
 * handle transaction data, that will live during the time of a single
@@ -529,45 +524,36 @@
 The web publisher handles the transaction:
 
 * commit / rollback is done automatically
-* you should not commit / rollback explicitly
 
-Because a session lives for a long time, and database connections are a limited
-resource, we can't bind a session to its own database connection for all its
-lifetime. The repository handles a pool of connections (4 by default), and it's
-responsible to attribute them as needed.
+* you should not commit / rollback explicitly, except if you really
+  need it
 
 Let's detail the process:
 
-1. an incoming RQL query comes from a client to the repository
+1. an incoming RQL query comes from a client to the web stack
 
-2. the repository attributes a database connection to the session
+2. the web stack opens an authenticated database connection for the
+   request, which is associated to a user session
 
-3. the repository's querier executes the query
+3. the query is executed (through the repository connection)
 
-4. this query may trigger hooks. Hooks and operation may execute some rql queries
-   through `_cw.execute`. Those queries go directly to the querier, hence don't
-   touch the database connection, they use the one attributed in 2.
+4. this query may trigger hooks. Hooks and operations may execute some rql queries
+   through `cnx.execute`.
 
 5. the repository gets the result of the query in 1. If it was a RQL read query,
    the database connection is released. If it was a write query, the connection
-   is then tied to the session until the transaction is commited or rollbacked.
+   is then tied to the session until the transaction is commited or rolled back.
 
 6. results are sent back to the client
 
 This implies several things:
 
-* when using a request, or code executed in hooks, this database connection
-  handling is totally transparent
+* when using a request, or code executed in hooks, this database
+  connection handling is totally transparent
 
-* however, take care when writing tests: you are usually faking / testing both the
-  server and the client side, so you have to decide when to use RepoAccess.client_cnx /
-  RepoAccess.repo_cnx. Ask yourself "where the code I want to test will be running,
-  client or repository side ?". The response is usually : use a client connection :)
-  However, if you really need using a server-side object:
-
-  - commit / rollback will free the database connection (unless explicitly told
-    not to do so).
-
-  - if you issue a query after that without asking for a database connection
-    (`session.get_cnxset()`), you will end up with a 'None type has no attribute
-    source()' error
+* however, take care when writing tests: you are usually faking /
+  testing both the server and the client side, so you have to decide
+  when to use RepoAccess.client_cnx or RepoAccess.repo_cnx. Ask
+  yourself "where will the code I want to test be running, client or
+  repository side?". The response is usually: use a repo (since the
+  "client connection" concept is going away in a couple of releases).
--- a/doc/book/en/tutorials/advanced/part02_security.rst	Thu Jul 17 11:08:56 2014 +0200
+++ b/doc/book/en/tutorials/advanced/part02_security.rst	Fri Jul 18 17:35:25 2014 +0200
@@ -142,7 +142,7 @@
 * `VISIBILITY_PERMISSIONS` provides read access to managers group, if
   `visibility` attribute's value is 'public', or if user (designed by the 'U'
   variable in the expression) is linked to the entity (the 'X' variable) through
-  the `may_read` permission
+  the `may_be_read_by` permission
 
 * we modify permissions of the entity types we use by importing them and
   modifying their `__permissions__` attribute
@@ -168,7 +168,7 @@
   commented entity.
 
 This kind of `active` rule will be done using CubicWeb's hook
-system. Hooks are triggered on database event such as addition of new
+system. Hooks are triggered on database events such as addition of a new
 entity or relation.
 
 The tricky part of the requirement is in *unless explicitly specified*, notably
@@ -223,9 +223,9 @@
   relation types to which the hook applies. To match a relation type, we use the
   hook specific `match_rtype` selector.
 
-* usage of `set_operation`: instead of adding an operation for each added entity,
-  set_operation allows to create a single one and to store entity's eids to be
-  processed in session's transaction data. This is a good pratice to avoid heavy
+* usage of `DataOperationMixIn`: instead of adding an operation for each added entity,
+  DataOperationMixIn allows to create a single one and to store entity's eids to be
+  processed in the transaction data. This is a good pratice to avoid heavy
   operations manipulation cost when creating a lot of entities in the same
   transaction.
 
@@ -314,51 +314,50 @@
     class SecurityTC(CubicWebTC):
 
 	def test_visibility_propagation(self):
-	    # create a user for later security checks
-	    toto = self.create_user('toto')
-	    # init some data using the default manager connection
-	    req = self.request()
-	    folder = req.create_entity('Folder',
-				       name=u'restricted',
-				       visibility=u'restricted')
-	    photo1 = req.create_entity('File',
-				       data_name=u'photo1.jpg',
-				       data=Binary('xxx'),
-				       filed_under=folder)
-	    self.commit()
-	    photo1.clear_all_caches() # good practice, avoid request cache effects
-	    # visibility propagation
-	    self.assertEquals(photo1.visibility, 'restricted')
-	    # unless explicitly specified
-	    photo2 = req.create_entity('File',
-				       data_name=u'photo2.jpg',
-				       data=Binary('xxx'),
-				       visibility=u'public',
-				       filed_under=folder)
-	    self.commit()
-	    self.assertEquals(photo2.visibility, 'public')
-	    # test security
-	    self.login('toto')
-	    req = self.request()
-	    self.assertEquals(len(req.execute('File X')), 1) # only the public one
-	    self.assertEquals(len(req.execute('Folder X')), 0) # restricted...
-	    # may_be_read_by propagation
-	    self.restore_connection()
-	    folder.cw_set(may_be_read_by=toto)
-	    self.commit()
-	    photo1.clear_all_caches()
-	    self.failUnless(photo1.may_be_read_by)
-	    # test security with permissions
-	    self.login('toto')
-	    req = self.request()
-	    self.assertEquals(len(req.execute('File X')), 2) # now toto has access to photo2
-	    self.assertEquals(len(req.execute('Folder X')), 1) # and to restricted folder
+
+            with self.admin_access.repo_cnx() as cnx:
+                # create a user for later security checks
+                toto = self.create_user(cnx, 'toto')
+                cnx.commit()
+                # init some data using the default manager connection
+                folder = cnx.create_entity('Folder',
+                                           name=u'restricted',
+    				           visibility=u'restricted')
+                photo1 = cnx.create_entity('File',
+    	                                   data_name=u'photo1.jpg',
+                                           data=Binary('xxx'),
+                                           filed_under=folder)
+                cnx.commit()
+                # visibility propagation
+                self.assertEquals(photo1.visibility, 'restricted')
+                # unless explicitly specified
+                photo2 = cnx.create_entity('File',
+                                           data_name=u'photo2.jpg',
+				           data=Binary('xxx'),
+				           visibility=u'public',
+				           filed_under=folder)
+                cnx.commit()
+                self.assertEquals(photo2.visibility, 'public')
+
+            with self.new_access('toto').repo_cnx() as cnx:
+                # test security
+                self.assertEqual(1, len(cnx.execute('File X'))) # only the public one
+                self.assertEqual(0, len(cnx.execute('Folder X'))) # restricted...
+                # may_be_read_by propagation
+                folder = cnx.entity_from_eid(folder.eid)
+                folder.cw_set(may_be_read_by=toto)
+                cnx.commit()
+                photo1 = cnx.entity_from_eid(photo1)
+                self.failUnless(photo1.may_be_read_by)
+                # test security with permissions
+                self.assertEquals(2, len(cnx.execute('File X'))) # now toto has access to photo2
+                self.assertEquals(1, len(cnx.execute('Folder X'))) # and to restricted folder
 
     if __name__ == '__main__':
 	from logilab.common.testlib import unittest_main
 	unittest_main()
 
-It's not complete, but show most things you'll want to do in tests: adding some
+It's not complete, but shows most things you'll want to do in tests: adding some
 content, creating users and connecting as them in the test, etc...
 
 To run it type:
@@ -394,7 +393,7 @@
 If you do some changes in your schema, you'll have to force regeneration of that
 database. You do that by removing the tmpdb files before running the test: ::
 
-    $ rm data/tmpdb*
+    $ rm data/database/tmpdb*
 
 
 .. Note::
@@ -407,12 +406,12 @@
 Step 4: writing the migration script and migrating the instance
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Prior to those changes, I  created an instance, feeded it with some data, so I
+Prior to those changes, I created an instance, fed it with some data, so I
 don't want to create a new one, but to migrate the existing one. Let's see how to
 do that.
 
 Migration commands should be put in the cube's *migration* directory, in a
-file named file:`<X.Y.Z>_Any.py` ('Any' being there mostly for historical reason).
+file named file:`<X.Y.Z>_Any.py` ('Any' being there mostly for historical reasons).
 
 Here I'll create a *migration/0.2.0_Any.py* file containing the following
 instructions:
@@ -423,11 +422,11 @@
   add_relation_type('visibility')
   sync_schema_props_perms()
 
-Then I update the version number in cube's *__pkginfo__.py* to 0.2.0. And
+Then I update the version number in the cube's *__pkginfo__.py* to 0.2.0. And
 that's it! Those instructions will:
 
 * update the instance's schema by adding our two new relations and update the
-  underlying database tables accordingly (the two first instructions)
+  underlying database tables accordingly (the first two instructions)
 
 * update schema's permissions definition (the last instruction)
 
--- a/entities/test/unittest_base.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/entities/test/unittest_base.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -21,7 +21,6 @@
 
 from logilab.common.testlib import unittest_main
 from logilab.common.decorators import clear_cache
-from logilab.common.interface import implements
 
 from cubicweb.devtools.testlib import CubicWebTC
 
@@ -31,114 +30,135 @@
 class BaseEntityTC(CubicWebTC):
 
     def setup_database(self):
-        req = self.request()
-        self.member = self.create_user(req, 'member')
-
+        with self.admin_access.repo_cnx() as cnx:
+            self.membereid = self.create_user(cnx, 'member').eid
+            cnx.commit()
 
 
 class MetadataTC(BaseEntityTC):
 
     def test_creator(self):
-        self.login(u'member')
-        entity = self.request().create_entity('Bookmark', title=u"hello", path=u'project/cubicweb')
-        self.commit()
-        self.assertEqual(entity.creator.eid, self.member.eid)
-        self.assertEqual(entity.dc_creator(), u'member')
+        with self.new_access('member').repo_cnx() as cnx:
+            entity = cnx.create_entity('Bookmark', title=u"hello", path=u'project/cubicweb')
+            cnx.commit()
+            self.assertEqual(entity.creator.eid, self.membereid)
+            self.assertEqual(entity.dc_creator(), u'member')
 
     def test_type(self):
         #dc_type may be translated
-        self.assertEqual(self.member.dc_type(), 'CWUser')
+        with self.admin_access.client_cnx() as cnx:
+            member = cnx.entity_from_eid(self.membereid)
+            self.assertEqual(member.dc_type(), 'CWUser')
 
     def test_cw_etype(self):
         #cw_etype is never translated
-        self.assertEqual(self.member.cw_etype, 'CWUser')
+        with self.admin_access.client_cnx() as cnx:
+            member = cnx.entity_from_eid(self.membereid)
+            self.assertEqual(member.cw_etype, 'CWUser')
 
     def test_entity_meta_attributes(self):
         # XXX move to yams
         self.assertEqual(self.schema['CWUser'].meta_attributes(), {})
-        self.assertEqual(dict((str(k), v) for k, v in self.schema['State'].meta_attributes().iteritems()),
+        self.assertEqual(dict((str(k), v)
+                              for k, v in self.schema['State'].meta_attributes().iteritems()),
                           {'description_format': ('format', 'description')})
 
     def test_fti_rql_method(self):
-        eclass = self.vreg['etypes'].etype_class('EmailAddress')
-        self.assertEqual(['Any X, ALIAS, ADDRESS WHERE X is EmailAddress, '
-                          'X alias ALIAS, X address ADDRESS'],
-                         eclass.cw_fti_index_rql_queries(self.request()))
+        with self.admin_access.web_request() as req:
+            eclass = self.vreg['etypes'].etype_class('EmailAddress')
+            self.assertEqual(['Any X, ALIAS, ADDRESS WHERE X is EmailAddress, '
+                              'X alias ALIAS, X address ADDRESS'],
+                             eclass.cw_fti_index_rql_queries(req))
 
 
 class EmailAddressTC(BaseEntityTC):
+
     def test_canonical_form(self):
-        email1 = self.execute('INSERT EmailAddress X: X address "maarten.ter.huurne@philips.com"').get_entity(0, 0)
-        email2 = self.execute('INSERT EmailAddress X: X address "maarten@philips.com"').get_entity(0, 0)
-        email3 = self.execute('INSERT EmailAddress X: X address "toto@logilab.fr"').get_entity(0, 0)
-        email1.cw_set(prefered_form=email2)
-        self.assertEqual(email1.prefered.eid, email2.eid)
-        self.assertEqual(email2.prefered.eid, email2.eid)
-        self.assertEqual(email3.prefered.eid, email3.eid)
+        with self.admin_access.repo_cnx() as cnx:
+            email1 = cnx.execute('INSERT EmailAddress X: '
+                                 'X address "maarten.ter.huurne@philips.com"').get_entity(0, 0)
+            email2 = cnx.execute('INSERT EmailAddress X: '
+                                 'X address "maarten@philips.com"').get_entity(0, 0)
+            email3 = cnx.execute('INSERT EmailAddress X: '
+                                 'X address "toto@logilab.fr"').get_entity(0, 0)
+            email1.cw_set(prefered_form=email2)
+            self.assertEqual(email1.prefered.eid, email2.eid)
+            self.assertEqual(email2.prefered.eid, email2.eid)
+            self.assertEqual(email3.prefered.eid, email3.eid)
 
     def test_mangling(self):
-        email = self.execute('INSERT EmailAddress X: X address "maarten.ter.huurne@philips.com"').get_entity(0, 0)
-        self.assertEqual(email.display_address(), 'maarten.ter.huurne@philips.com')
-        self.assertEqual(email.printable_value('address'), 'maarten.ter.huurne@philips.com')
-        self.vreg.config.global_set_option('mangle-emails', True)
-        try:
-            self.assertEqual(email.display_address(), 'maarten.ter.huurne at philips dot com')
-            self.assertEqual(email.printable_value('address'), 'maarten.ter.huurne at philips dot com')
-            email = self.execute('INSERT EmailAddress X: X address "syt"').get_entity(0, 0)
-            self.assertEqual(email.display_address(), 'syt')
-            self.assertEqual(email.printable_value('address'), 'syt')
-        finally:
-            self.vreg.config.global_set_option('mangle-emails', False)
+        with self.admin_access.repo_cnx() as cnx:
+            email = cnx.execute('INSERT EmailAddress X: X address "maarten.ter.huurne@philips.com"').get_entity(0, 0)
+            self.assertEqual(email.display_address(), 'maarten.ter.huurne@philips.com')
+            self.assertEqual(email.printable_value('address'), 'maarten.ter.huurne@philips.com')
+            self.vreg.config.global_set_option('mangle-emails', True)
+            try:
+                self.assertEqual(email.display_address(), 'maarten.ter.huurne at philips dot com')
+                self.assertEqual(email.printable_value('address'), 'maarten.ter.huurne at philips dot com')
+                email = cnx.execute('INSERT EmailAddress X: X address "syt"').get_entity(0, 0)
+                self.assertEqual(email.display_address(), 'syt')
+                self.assertEqual(email.printable_value('address'), 'syt')
+            finally:
+                self.vreg.config.global_set_option('mangle-emails', False)
 
     def test_printable_value_escape(self):
-        email = self.execute('INSERT EmailAddress X: X address "maarten&ter@philips.com"').get_entity(0, 0)
-        self.assertEqual(email.printable_value('address'), 'maarten&amp;ter@philips.com')
-        self.assertEqual(email.printable_value('address', format='text/plain'), 'maarten&ter@philips.com')
+        with self.admin_access.repo_cnx() as cnx:
+            email = cnx.execute('INSERT EmailAddress X: '
+                                'X address "maarten&ter@philips.com"').get_entity(0, 0)
+            self.assertEqual(email.printable_value('address'),
+                             'maarten&amp;ter@philips.com')
+            self.assertEqual(email.printable_value('address', format='text/plain'),
+                             'maarten&ter@philips.com')
 
 class CWUserTC(BaseEntityTC):
 
     def test_complete(self):
-        e = self.execute('CWUser X WHERE X login "admin"').get_entity(0, 0)
-        e.complete()
+        with self.admin_access.repo_cnx() as cnx:
+            e = cnx.execute('CWUser X WHERE X login "admin"').get_entity(0, 0)
+            e.complete()
 
     def test_matching_groups(self):
-        e = self.execute('CWUser X WHERE X login "admin"').get_entity(0, 0)
-        self.assertTrue(e.matching_groups('managers'))
-        self.assertFalse(e.matching_groups('xyz'))
-        self.assertTrue(e.matching_groups(('xyz', 'managers')))
-        self.assertFalse(e.matching_groups(('xyz', 'abcd')))
+        with self.admin_access.repo_cnx() as cnx:
+            e = cnx.execute('CWUser X WHERE X login "admin"').get_entity(0, 0)
+            self.assertTrue(e.matching_groups('managers'))
+            self.assertFalse(e.matching_groups('xyz'))
+            self.assertTrue(e.matching_groups(('xyz', 'managers')))
+            self.assertFalse(e.matching_groups(('xyz', 'abcd')))
 
     def test_dc_title_and_name(self):
-        e = self.execute('CWUser U WHERE U login "member"').get_entity(0, 0)
-        self.assertEqual(e.dc_title(), 'member')
-        self.assertEqual(e.name(), 'member')
-        e.cw_set(firstname=u'bouah')
-        self.assertEqual(e.dc_title(), 'member')
-        self.assertEqual(e.name(), u'bouah')
-        e.cw_set(surname=u'lôt')
-        self.assertEqual(e.dc_title(), 'member')
-        self.assertEqual(e.name(), u'bouah lôt')
+        with self.admin_access.repo_cnx() as cnx:
+            e = cnx.execute('CWUser U WHERE U login "member"').get_entity(0, 0)
+            self.assertEqual(e.dc_title(), 'member')
+            self.assertEqual(e.name(), 'member')
+            e.cw_set(firstname=u'bouah')
+            self.assertEqual(e.dc_title(), 'member')
+            self.assertEqual(e.name(), u'bouah')
+            e.cw_set(surname=u'lôt')
+            self.assertEqual(e.dc_title(), 'member')
+            self.assertEqual(e.name(), u'bouah lôt')
 
     def test_allowed_massmail_keys(self):
-        e = self.execute('CWUser U WHERE U login "member"').get_entity(0, 0)
-        # Bytes/Password attributes should be omited
-        self.assertEqual(e.cw_adapt_to('IEmailable').allowed_massmail_keys(),
-                          set(('surname', 'firstname', 'login', 'last_login_time',
-                               'creation_date', 'modification_date', 'cwuri', 'eid'))
-                          )
+        with self.admin_access.repo_cnx() as cnx:
+            e = cnx.execute('CWUser U WHERE U login "member"').get_entity(0, 0)
+            # Bytes/Password attributes should be omited
+            self.assertEqual(e.cw_adapt_to('IEmailable').allowed_massmail_keys(),
+                              set(('surname', 'firstname', 'login', 'last_login_time',
+                                   'creation_date', 'modification_date', 'cwuri', 'eid'))
+                              )
 
     def test_cw_instantiate_object_relation(self):
         """ a weird non regression test """
-        e = self.execute('CWUser U WHERE U login "member"').get_entity(0, 0)
-        self.request().create_entity('CWGroup', name=u'logilab', reverse_in_group=e)
+        with self.admin_access.repo_cnx() as cnx:
+            e = cnx.execute('CWUser U WHERE U login "member"').get_entity(0, 0)
+            cnx.create_entity('CWGroup', name=u'logilab', reverse_in_group=e)
 
 
 class HTMLtransformTC(BaseEntityTC):
 
     def test_sanitized_html(self):
-        r = self.request()
-        c = r.create_entity('Company', name=u'Babar',
-                            description=u"""
+        with self.admin_access.repo_cnx() as cnx:
+            c = cnx.create_entity('Company', name=u'Babar',
+                                  description=u"""
 Title
 =====
 
@@ -148,10 +168,12 @@
 
    <script>alert("coucou")</script>
 """, description_format=u'text/rest')
-        self.commit()
-        c.cw_clear_all_caches()
-        self.assertIn('alert', c.printable_value('description', format='text/plain'))
-        self.assertNotIn('alert', c.printable_value('description', format='text/html'))
+            cnx.commit()
+            c.cw_clear_all_caches()
+            self.assertIn('alert',
+                          c.printable_value('description', format='text/plain'))
+            self.assertNotIn('alert',
+                             c.printable_value('description', format='text/html'))
 
 
 class SpecializedEntityClassesTC(CubicWebTC):
--- a/entity.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/entity.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -344,7 +344,8 @@
                 cls.warning('skipping fetch_attr %s defined in %s (not found in schema)',
                             attr, cls.__regid__)
                 continue
-            rdef = eschema.rdef(attr)
+            # XXX takefirst=True to remove warning triggered by ambiguous inlined relations
+            rdef = eschema.rdef(attr, takefirst=True)
             if not user.matching_groups(rdef.get_groups('read')):
                 continue
             if rschema.final or rdef.cardinality[0] in '?1':
@@ -793,8 +794,9 @@
             # skip already defined relations
             if getattr(self, rschema.type):
                 continue
+            # XXX takefirst=True to remove warning triggered by ambiguous relations
+            rdef = self.e_schema.rdef(rschema, takefirst=True)
             # skip composite relation
-            rdef = self.e_schema.rdef(rschema)
             if rdef.composite:
                 continue
             # skip relation with card in ?1 else we either change the copied
@@ -813,7 +815,8 @@
                 continue
             if rschema.type in skip_copy_for['object']:
                 continue
-            rdef = self.e_schema.rdef(rschema, 'object')
+            # XXX takefirst=True to remove warning triggered by ambiguous relations
+            rdef = self.e_schema.rdef(rschema, 'object', takefirst=True)
             # skip composite relation
             if rdef.composite:
                 continue
--- a/etwist/server.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/etwist/server.py	Fri Jul 18 17:35:25 2014 +0200
@@ -69,6 +69,7 @@
                 # if pyro is enabled, we have to register to the pyro name
                 # server, create a pyro daemon, and create a task to handle pyro
                 # requests
+                self.appli.repo.warning('remote repository access through pyro is deprecated')
                 self.pyro_daemon = self.appli.repo.pyro_register()
                 self.pyro_listen_timeout = 0.02
                 self.appli.repo.looping_task(1, self.pyro_loop_event)
--- a/ext/test/unittest_rest.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/ext/test/unittest_rest.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -21,18 +21,23 @@
 from cubicweb.ext.rest import rest_publish
 
 class RestTC(CubicWebTC):
-    def context(self):
-        return self.execute('CWUser X WHERE X login "admin"').get_entity(0, 0)
+
+    def context(self, req):
+        return req.execute('CWUser X WHERE X login "admin"').get_entity(0, 0)
 
     def test_eid_role(self):
-        context = self.context()
-        self.assertEqual(rest_publish(context, ':eid:`%s`' % context.eid),
-                          '<p><a class="reference" href="http://testing.fr/cubicweb/cwuser/admin">#%s</a></p>\n' % context.eid)
-        self.assertEqual(rest_publish(context, ':eid:`%s:some text`' %  context.eid),
-                          '<p><a class="reference" href="http://testing.fr/cubicweb/cwuser/admin">some text</a></p>\n')
+        with self.admin_access.web_request() as req:
+            context = self.context(req)
+            self.assertEqual(rest_publish(context, ':eid:`%s`' % context.eid),
+                             '<p><a class="reference" href="http://testing.fr/cubicweb/cwuser/admin">'
+                             '#%s</a></p>\n' % context.eid)
+            self.assertEqual(rest_publish(context, ':eid:`%s:some text`' %  context.eid),
+                             '<p><a class="reference" href="http://testing.fr/cubicweb/cwuser/admin">'
+                             'some text</a></p>\n')
 
     def test_bad_rest_no_crash(self):
-        data = rest_publish(self.context(), '''
+        with self.admin_access.web_request() as req:
+            rest_publish(self.context(req), '''
 | card | implication     |
 --------------------------
 | 1-1  | N1 = N2         |
@@ -55,159 +60,172 @@
 
 
     def test_rql_role_with_vid(self):
-        context = self.context()
-        out = rest_publish(context, ':rql:`Any X WHERE X is CWUser:table`')
-        self.assertTrue(out.endswith('<a href="http://testing.fr/cubicweb/cwuser/anon" title="">anon</a>'
-                                     '</td></tr>\n</tbody></table></div></p>\n'))
+        with self.admin_access.web_request() as req:
+            context = self.context(req)
+            out = rest_publish(context, ':rql:`Any X WHERE X is CWUser:table`')
+            self.assertTrue(out.endswith('<a href="http://testing.fr/cubicweb/cwuser/anon" '
+                                         'title="">anon</a></td></tr>\n</tbody></table>'
+                                         '</div></p>\n'))
 
     def test_rql_role_with_vid_empty_rset(self):
-        context = self.context()
-        out = rest_publish(context, ':rql:`Any X WHERE X is CWUser, X login "nono":table`')
-        self.assertTrue(out.endswith('<p><div class="searchMessage"><strong>No result matching query</strong></div>\n</p>\n'))
+        with self.admin_access.web_request() as req:
+            context = self.context(req)
+            out = rest_publish(context, ':rql:`Any X WHERE X is CWUser, X login "nono":table`')
+            self.assertTrue(out.endswith('<p><div class="searchMessage"><strong>'
+                                         'No result matching query</strong></div>\n</p>\n'))
 
     def test_rql_role_with_unknown_vid(self):
-        context = self.context()
-        out = rest_publish(context, ':rql:`Any X WHERE X is CWUser:toto`')
-        self.assertTrue(out.startswith("<p>an error occurred while interpreting this rql directive: ObjectNotFound(u'toto',)</p>"))
+        with self.admin_access.web_request() as req:
+            context = self.context(req)
+            out = rest_publish(context, ':rql:`Any X WHERE X is CWUser:toto`')
+            self.assertTrue(out.startswith("<p>an error occurred while interpreting this "
+                                           "rql directive: ObjectNotFound(u'toto',)</p>"))
 
     def test_rql_role_without_vid(self):
-        context = self.context()
-        out = rest_publish(context, ':rql:`Any X WHERE X is CWUser`')
-        self.assertEqual(out, u'<p><h1>CWUser_plural</h1><div class="section"><a href="http://testing.fr/cubicweb/cwuser/admin" title="">admin</a></div><div class="section"><a href="http://testing.fr/cubicweb/cwuser/anon" title="">anon</a></div></p>\n')
+        with self.admin_access.web_request() as req:
+            context = self.context(req)
+            out = rest_publish(context, ':rql:`Any X WHERE X is CWUser`')
+            self.assertEqual(out, u'<p><h1>CWUser_plural</h1><div class="section">'
+                             '<a href="http://testing.fr/cubicweb/cwuser/admin" title="">admin</a>'
+                             '</div><div class="section">'
+                             '<a href="http://testing.fr/cubicweb/cwuser/anon" title="">anon</a>'
+                             '</div></p>\n')
 
     def test_bookmark_role(self):
-        context = self.context()
-        rset = self.execute('INSERT Bookmark X: X title "hello", X path "/view?rql=Any X WHERE X is CWUser"')
-        eid = rset[0][0]
-        out = rest_publish(context, ':bookmark:`%s`' % eid)
-        self.assertEqual(out, u'<p><h1>CWUser_plural</h1><div class="section"><a href="http://testing.fr/cubicweb/cwuser/admin" title="">admin</a></div><div class="section"><a href="http://testing.fr/cubicweb/cwuser/anon" title="">anon</a></div></p>\n')
+        with self.admin_access.web_request() as req:
+            context = self.context(req)
+            rset = req.execute('INSERT Bookmark X: X title "hello", X path '
+                               '"/view?rql=Any X WHERE X is CWUser"')
+            eid = rset[0][0]
+            out = rest_publish(context, ':bookmark:`%s`' % eid)
+            self.assertEqual(out, u'<p><h1>CWUser_plural</h1><div class="section">'
+                             '<a href="http://testing.fr/cubicweb/cwuser/admin" title="">admin'
+                             '</a></div><div class="section">'
+                             '<a href="http://testing.fr/cubicweb/cwuser/anon" title="">anon'
+                             '</a></div></p>\n')
 
     def test_rqltable_nocontent(self):
-        context = self.context()
-        out = rest_publish(context, """.. rql-table::""")
-        self.assertIn("System Message: ERROR", out)
-        self.assertIn("Content block expected for the &quot;rql-table&quot; "
-                      "directive; none found" , out)
+        with self.admin_access.web_request() as req:
+            context = self.context(req)
+            out = rest_publish(context, """.. rql-table::""")
+            self.assertIn("System Message: ERROR", out)
+            self.assertIn("Content block expected for the &quot;rql-table&quot; "
+                          "directive; none found" , out)
 
     def test_rqltable_norset(self):
-        context = self.context()
-        rql = "Any X WHERE X is CWUser, X firstname 'franky'"
-        out = rest_publish(
-            context, """\
+        with self.admin_access.web_request() as req:
+            context = self.context(req)
+            rql = "Any X WHERE X is CWUser, X firstname 'franky'"
+            out = rest_publish(
+                context, """\
 .. rql-table::
 
-            %(rql)s""" % {'rql': rql})
-        self.assertIn("System Message: WARNING", out)
-        self.assertIn("empty result set", out)
+                %(rql)s""" % {'rql': rql})
+            self.assertIn("System Message: WARNING", out)
+            self.assertIn("empty result set", out)
 
     def test_rqltable_nooptions(self):
-        rql = """Any S,F,L WHERE X is CWUser, X surname S,
-                                 X firstname F, X login L"""
-        out = rest_publish(
-            self.context(), """\
+        with self.admin_access.web_request() as req:
+            rql = "Any S,F,L WHERE X is CWUser, X surname S, X firstname F, X login L"
+            out = rest_publish(
+                self.context(req), """\
 .. rql-table::
 
    %(rql)s
-            """ % {'rql': rql})
-        req = self.request()
-        view = self.vreg['views'].select('table', req, rset=req.execute(rql))
-        self.assertEqual(view.render(w=None)[49:], out[49:])
+                """ % {'rql': rql})
+            view = self.vreg['views'].select('table', req, rset=req.execute(rql))
+            self.assertEqual(view.render(w=None)[49:], out[49:])
 
     def test_rqltable_vid(self):
-        rql = """Any S,F,L WHERE X is CWUser, X surname S,
-                                 X firstname F, X login L"""
-        vid = 'mytable'
-        out = rest_publish(
-            self.context(), """\
+        with self.admin_access.web_request() as req:
+            rql = "Any S,F,L WHERE X is CWUser, X surname S, X firstname F, X login L"
+            vid = 'mytable'
+            out = rest_publish(
+                self.context(req), """\
 .. rql-table::
    :vid: %(vid)s
 
    %(rql)s
-            """ % {'rql': rql, 'vid': vid})
-        req = self.request()
-        view = self.vreg['views'].select(vid, req, rset=req.execute(rql))
-        self.assertEqual(view.render(w=None)[49:], out[49:])
-        self.assertIn(vid, out[:49])
+                """ % {'rql': rql, 'vid': vid})
+            view = self.vreg['views'].select(vid, req, rset=req.execute(rql))
+            self.assertEqual(view.render(w=None)[49:], out[49:])
+            self.assertIn(vid, out[:49])
 
     def test_rqltable_badvid(self):
-        rql = """Any S,F,L WHERE X is CWUser, X surname S,
-                                 X firstname F, X login L"""
-        vid = 'mytabel'
-        out = rest_publish(
-            self.context(), """\
+        with self.admin_access.web_request() as req:
+            rql = "Any S,F,L WHERE X is CWUser, X surname S, X firstname F, X login L"
+            vid = 'mytabel'
+            out = rest_publish(
+                self.context(req), """\
 .. rql-table::
    :vid: %(vid)s
 
    %(rql)s
-            """ % {'rql': rql, 'vid': vid})
-        self.assertIn("fail to select '%s' view" % vid, out)
+                """ % {'rql': rql, 'vid': vid})
+            self.assertIn("fail to select '%s' view" % vid, out)
 
     def test_rqltable_headers(self):
-        rql = """Any S,F,L WHERE X is CWUser, X surname S,
-                                 X firstname F, X login L"""
-        headers = ["nom", "prenom", "identifiant"]
-        out = rest_publish(
-            self.context(), """\
-.. rql-table::
-   :headers: %(headers)s
-
-   %(rql)s
-            """ % {'rql': rql, 'headers': ', '.join(headers)})
-        req = self.request()
-        view = self.vreg['views'].select('table', req, rset=req.execute(rql))
-        view.headers = headers
-        self.assertEqual(view.render(w=None)[49:], out[49:])
-
-    def test_rqltable_headers_missing(self):
-        rql = """Any S,F,L WHERE X is CWUser, X surname S,
-                                 X firstname F, X login L"""
-        headers = ["nom", "", "identifiant"]
-        out = rest_publish(
-            self.context(), """\
+        with self.admin_access.web_request() as req:
+            rql = "Any S,F,L WHERE X is CWUser, X surname S, X firstname F, X login L"
+            headers = ["nom", "prenom", "identifiant"]
+            out = rest_publish(
+                self.context(req), """\
 .. rql-table::
    :headers: %(headers)s
 
    %(rql)s
-            """ % {'rql': rql, 'headers': ', '.join(headers)})
-        req = self.request()
-        view = self.vreg['views'].select('table', req, rset=req.execute(rql))
-        view.headers = [headers[0], None, headers[2]]
-        self.assertEqual(view.render(w=None)[49:], out[49:])
+                """ % {'rql': rql, 'headers': ', '.join(headers)})
+            view = self.vreg['views'].select('table', req, rset=req.execute(rql))
+            view.headers = headers
+            self.assertEqual(view.render(w=None)[49:], out[49:])
 
-    def test_rqltable_headers_missing_edges(self):
-        rql = """Any S,F,L WHERE X is CWUser, X surname S,
-                                 X firstname F, X login L"""
-        headers = [" ", "prenom", ""]
-        out = rest_publish(
-            self.context(), """\
+    def test_rqltable_headers_missing(self):
+        with self.admin_access.web_request() as req:
+            rql = "Any S,F,L WHERE X is CWUser, X surname S, X firstname F, X login L"
+            headers = ["nom", "", "identifiant"]
+            out = rest_publish(
+                self.context(req), """\
 .. rql-table::
    :headers: %(headers)s
 
    %(rql)s
-            """ % {'rql': rql, 'headers': ', '.join(headers)})
-        req = self.request()
-        view = self.vreg['views'].select('table', req, rset=req.execute(rql))
-        view.headers = [None, headers[1], None]
-        self.assertEqual(view.render(w=None)[49:], out[49:])
+                """ % {'rql': rql, 'headers': ', '.join(headers)})
+            view = self.vreg['views'].select('table', req, rset=req.execute(rql))
+            view.headers = [headers[0], None, headers[2]]
+            self.assertEqual(view.render(w=None)[49:], out[49:])
+
+    def test_rqltable_headers_missing_edges(self):
+        with self.admin_access.web_request() as req:
+            rql = "Any S,F,L WHERE X is CWUser, X surname S, X firstname F, X login L"
+            headers = [" ", "prenom", ""]
+            out = rest_publish(
+                self.context(req), """\
+.. rql-table::
+   :headers: %(headers)s
+
+   %(rql)s
+                """ % {'rql': rql, 'headers': ', '.join(headers)})
+            view = self.vreg['views'].select('table', req, rset=req.execute(rql))
+            view.headers = [None, headers[1], None]
+            self.assertEqual(view.render(w=None)[49:], out[49:])
 
     def test_rqltable_colvids(self):
-        rql = """Any X,S,F,L WHERE X is CWUser, X surname S,
-                                   X firstname F, X login L"""
-        colvids = {0: "oneline"}
-        out = rest_publish(
-            self.context(), """\
+        with self.admin_access.web_request() as req:
+            rql = "Any X,S,F,L WHERE X is CWUser, X surname S, X firstname F, X login L"
+            colvids = {0: "oneline"}
+            out = rest_publish(
+                self.context(req), """\
 .. rql-table::
    :colvids: %(colvids)s
 
    %(rql)s
-            """ % {'rql': rql,
-                   'colvids': ', '.join(["%d=%s" % (k, v)
-                                         for k, v in colvids.iteritems()])
-                  })
-        req = self.request()
-        view = self.vreg['views'].select('table', req, rset=req.execute(rql))
-        view.cellvids = colvids
-        self.assertEqual(view.render(w=None)[49:], out[49:])
+                """ % {'rql': rql,
+                       'colvids': ', '.join(["%d=%s" % (k, v)
+                                             for k, v in colvids.iteritems()])
+                   })
+            view = self.vreg['views'].select('table', req, rset=req.execute(rql))
+            view.cellvids = colvids
+            self.assertEqual(view.render(w=None)[49:], out[49:])
 
 
 if __name__ == '__main__':
--- a/hooks/syncschema.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/hooks/syncschema.py	Fri Jul 18 17:35:25 2014 +0200
@@ -653,6 +653,9 @@
         else:
             self.critical('constraint %s for rdef %s was missing or already removed',
                           self.oldcstr, rdef)
+        if cnx.deleted_in_transaction(rdef.eid):
+            # don't try to alter a table that's going away (or is already gone)
+            return
         # then update database: alter the physical schema on size/unique
         # constraint changes
         syssource = cnx.repo.system_source
--- a/hooks/test/unittest_bookmarks.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/hooks/test/unittest_bookmarks.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -22,16 +22,17 @@
 
 
     def test_auto_delete_bookmarks(self):
-        beid = self.execute('INSERT Bookmark X: X title "hop", X path "view", X bookmarked_by U '
-                            'WHERE U login "admin"')[0][0]
-        self.execute('SET X bookmarked_by U WHERE U login "anon"')
-        self.commit()
-        self.execute('DELETE X bookmarked_by U WHERE U login "admin"')
-        self.commit()
-        self.assertTrue(self.execute('Any X WHERE X eid %(x)s', {'x': beid}))
-        self.execute('DELETE X bookmarked_by U WHERE U login "anon"')
-        self.commit()
-        self.assertFalse(self.execute('Any X WHERE X eid %(x)s', {'x': beid}))
+        with self.admin_access.repo_cnx() as cnx:
+            beid = cnx.execute('INSERT Bookmark X: X title "hop", X path "view", X bookmarked_by U '
+                               'WHERE U login "admin"')[0][0]
+            cnx.execute('SET X bookmarked_by U WHERE U login "anon"')
+            cnx.commit()
+            cnx.execute('DELETE X bookmarked_by U WHERE U login "admin"')
+            cnx.commit()
+            self.assertTrue(cnx.execute('Any X WHERE X eid %(x)s', {'x': beid}))
+            cnx.execute('DELETE X bookmarked_by U WHERE U login "anon"')
+            cnx.commit()
+            self.assertFalse(cnx.execute('Any X WHERE X eid %(x)s', {'x': beid}))
 
 if __name__ == '__main__':
     unittest_main()
--- a/hooks/test/unittest_hooks.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/hooks/test/unittest_hooks.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -30,177 +30,189 @@
 class CoreHooksTC(CubicWebTC):
 
     def test_inlined(self):
-        self.assertEqual(self.repo.schema['sender'].inlined, True)
-        self.execute('INSERT EmailAddress X: X address "toto@logilab.fr", X alias "hop"')
-        self.execute('INSERT EmailPart X: X content_format "text/plain", X ordernum 1, X content "this is a test"')
-        eeid = self.execute('INSERT Email X: X messageid "<1234>", X subject "test", X sender Y, X recipients Y, X parts P '
-                            'WHERE Y is EmailAddress, P is EmailPart')[0][0]
-        self.execute('SET X sender Y WHERE X is Email, Y is EmailAddress')
-        rset = self.execute('Any S WHERE X sender S, X eid %s' % eeid)
-        self.assertEqual(len(rset), 1)
+        with self.admin_access.repo_cnx() as cnx:
+            self.assertEqual(self.repo.schema['sender'].inlined, True)
+            cnx.execute('INSERT EmailAddress X: X address "toto@logilab.fr", X alias "hop"')
+            cnx.execute('INSERT EmailPart X: X content_format "text/plain", X ordernum 1, '
+                        'X content "this is a test"')
+            eeid = cnx.execute('INSERT Email X: X messageid "<1234>", X subject "test", '
+                               'X sender Y, X recipients Y, X parts P '
+                               'WHERE Y is EmailAddress, P is EmailPart')[0][0]
+            cnx.execute('SET X sender Y WHERE X is Email, Y is EmailAddress')
+            rset = cnx.execute('Any S WHERE X sender S, X eid %s' % eeid)
+            self.assertEqual(len(rset), 1)
 
     def test_symmetric(self):
-        req = self.request()
-        u1 = self.create_user(req, u'1')
-        u2 = self.create_user(req, u'2')
-        u3 = self.create_user(req, u'3')
-        ga = req.create_entity('CWGroup', name=u'A')
-        gb = req.create_entity('CWGroup', name=u'B')
-        u1.cw_set(friend=u2)
-        u2.cw_set(friend=u3)
-        ga.cw_set(friend=gb)
-        ga.cw_set(friend=u1)
-        self.commit()
-        req = self.request()
-        for l1, l2 in ((u'1', u'2'),
-                       (u'2', u'3')):
-            self.assertTrue(req.execute('Any U1,U2 WHERE U1 friend U2, U1 login %(l1)s, U2 login %(l2)s',
-                                        {'l1': l1, 'l2': l2}))
-            self.assertTrue(req.execute('Any U1,U2 WHERE U2 friend U1, U1 login %(l1)s, U2 login %(l2)s',
-                                        {'l1': l1, 'l2': l2}))
-        self.assertTrue(req.execute('Any GA,GB WHERE GA friend GB, GA name "A", GB name "B"'))
-        self.assertTrue(req.execute('Any GA,GB WHERE GB friend GA, GA name "A", GB name "B"'))
-        self.assertTrue(req.execute('Any GA,U1 WHERE GA friend U1, GA name "A", U1 login "1"'))
-        self.assertTrue(req.execute('Any GA,U1 WHERE U1 friend GA, GA name "A", U1 login "1"'))
-        self.assertFalse(req.execute('Any GA,U WHERE GA friend U, GA name "A", U login "2"'))
-        for l1, l2 in ((u'1', u'3'),
-                       (u'3', u'1')):
-            self.assertFalse(req.execute('Any U1,U2 WHERE U1 friend U2, U1 login %(l1)s, U2 login %(l2)s',
-                                         {'l1': l1, 'l2': l2}))
-            self.assertFalse(req.execute('Any U1,U2 WHERE U2 friend U1, U1 login %(l1)s, U2 login %(l2)s',
-                                         {'l1': l1, 'l2': l2}))
+        with self.admin_access.repo_cnx() as cnx:
+            u1 = self.create_user(cnx, u'1')
+            u2 = self.create_user(cnx, u'2')
+            u3 = self.create_user(cnx, u'3')
+            ga = cnx.create_entity('CWGroup', name=u'A')
+            gb = cnx.create_entity('CWGroup', name=u'B')
+            u1.cw_set(friend=u2)
+            u2.cw_set(friend=u3)
+            ga.cw_set(friend=gb)
+            ga.cw_set(friend=u1)
+            cnx.commit()
+            for l1, l2 in ((u'1', u'2'),
+                           (u'2', u'3')):
+                self.assertTrue(cnx.execute('Any U1,U2 WHERE U1 friend U2, U1 login %(l1)s, U2 login %(l2)s',
+                                            {'l1': l1, 'l2': l2}))
+                self.assertTrue(cnx.execute('Any U1,U2 WHERE U2 friend U1, U1 login %(l1)s, U2 login %(l2)s',
+                                            {'l1': l1, 'l2': l2}))
+            self.assertTrue(cnx.execute('Any GA,GB WHERE GA friend GB, GA name "A", GB name "B"'))
+            self.assertTrue(cnx.execute('Any GA,GB WHERE GB friend GA, GA name "A", GB name "B"'))
+            self.assertTrue(cnx.execute('Any GA,U1 WHERE GA friend U1, GA name "A", U1 login "1"'))
+            self.assertTrue(cnx.execute('Any GA,U1 WHERE U1 friend GA, GA name "A", U1 login "1"'))
+            self.assertFalse(cnx.execute('Any GA,U WHERE GA friend U, GA name "A", U login "2"'))
+            for l1, l2 in ((u'1', u'3'),
+                           (u'3', u'1')):
+                self.assertFalse(cnx.execute('Any U1,U2 WHERE U1 friend U2, U1 login %(l1)s, U2 login %(l2)s',
+                                             {'l1': l1, 'l2': l2}))
+                self.assertFalse(cnx.execute('Any U1,U2 WHERE U2 friend U1, U1 login %(l1)s, U2 login %(l2)s',
+                                             {'l1': l1, 'l2': l2}))
 
     def test_html_tidy_hook(self):
-        req = self.request()
-        entity = req.create_entity('Workflow', name=u'wf1',
-                                   description_format=u'text/html',
-                                   description=u'yo')
-        self.assertEqual(entity.description, u'yo')
-        entity = req.create_entity('Workflow', name=u'wf2',
-                                   description_format=u'text/html',
-                                   description=u'<b>yo')
-        self.assertEqual(entity.description, u'<b>yo</b>')
-        entity = req.create_entity('Workflow', name=u'wf3',
-                                   description_format=u'text/html',
-                                   description=u'<b>yo</b>')
-        self.assertEqual(entity.description, u'<b>yo</b>')
-        entity = req.create_entity('Workflow', name=u'wf4',
-                                   description_format=u'text/html',
-                                   description=u'<b>R&D</b>')
-        self.assertEqual(entity.description, u'<b>R&amp;D</b>')
-        entity = req.create_entity('Workflow', name=u'wf5',
-                                   description_format=u'text/html',
-                                   description=u"<div>c&apos;est <b>l'ét&eacute;")
-        self.assertEqual(entity.description, u"<div>c'est <b>l'été</b></div>")
+        with self.admin_access.client_cnx() as cnx:
+            entity = cnx.create_entity('Workflow', name=u'wf1',
+                                       description_format=u'text/html',
+                                       description=u'yo')
+            self.assertEqual(entity.description, u'yo')
+            entity = cnx.create_entity('Workflow', name=u'wf2',
+                                       description_format=u'text/html',
+                                       description=u'<b>yo')
+            self.assertEqual(entity.description, u'<b>yo</b>')
+            entity = cnx.create_entity('Workflow', name=u'wf3',
+                                       description_format=u'text/html',
+                                       description=u'<b>yo</b>')
+            self.assertEqual(entity.description, u'<b>yo</b>')
+            entity = cnx.create_entity('Workflow', name=u'wf4',
+                                       description_format=u'text/html',
+                                       description=u'<b>R&D</b>')
+            self.assertEqual(entity.description, u'<b>R&amp;D</b>')
+            entity = cnx.create_entity('Workflow', name=u'wf5',
+                                       description_format=u'text/html',
+                                       description=u"<div>c&apos;est <b>l'ét&eacute;")
+            self.assertEqual(entity.description, u"<div>c'est <b>l'été</b></div>")
 
     def test_nonregr_html_tidy_hook_no_update(self):
-        entity = self.request().create_entity('Workflow', name=u'wf1',
-                                              description_format=u'text/html',
-                                              description=u'yo')
-        entity.cw_set(name=u'wf2')
-        self.assertEqual(entity.description, u'yo')
-        entity.cw_set(description=u'R&D<p>yo')
-        self.assertEqual(entity.description, u'R&amp;D<p>yo</p>')
+        with self.admin_access.client_cnx() as cnx:
+            entity = cnx.create_entity('Workflow', name=u'wf1',
+                                       description_format=u'text/html',
+                                       description=u'yo')
+            entity.cw_set(name=u'wf2')
+            self.assertEqual(entity.description, u'yo')
+            entity.cw_set(description=u'R&D<p>yo')
+            self.assertEqual(entity.description, u'R&amp;D<p>yo</p>')
 
     def test_metadata_cwuri(self):
-        entity = self.request().create_entity('Workflow', name=u'wf1')
-        self.assertEqual(entity.cwuri, self.repo.config['base-url'] + str(entity.eid))
+        with self.admin_access.repo_cnx() as cnx:
+            entity = cnx.create_entity('Workflow', name=u'wf1')
+            self.assertEqual(entity.cwuri, self.repo.config['base-url'] + str(entity.eid))
 
     def test_metadata_creation_modification_date(self):
-        _now = datetime.now()
-        entity = self.request().create_entity('Workflow', name=u'wf1')
-        self.assertEqual((entity.creation_date - _now).seconds, 0)
-        self.assertEqual((entity.modification_date - _now).seconds, 0)
+        with self.admin_access.repo_cnx() as cnx:
+            _now = datetime.now()
+            entity = cnx.create_entity('Workflow', name=u'wf1')
+            self.assertEqual((entity.creation_date - _now).seconds, 0)
+            self.assertEqual((entity.modification_date - _now).seconds, 0)
 
     def test_metadata_created_by(self):
-        entity = self.request().create_entity('Bookmark', title=u'wf1', path=u'/view')
-        self.commit() # fire operations
-        self.assertEqual(len(entity.created_by), 1) # make sure we have only one creator
-        self.assertEqual(entity.created_by[0].eid, self.session.user.eid)
+        with self.admin_access.repo_cnx() as cnx:
+            entity = cnx.create_entity('Bookmark', title=u'wf1', path=u'/view')
+            cnx.commit() # fire operations
+            self.assertEqual(len(entity.created_by), 1) # make sure we have only one creator
+            self.assertEqual(entity.created_by[0].eid, self.session.user.eid)
 
     def test_metadata_owned_by(self):
-        entity = self.request().create_entity('Bookmark', title=u'wf1', path=u'/view')
-        self.commit() # fire operations
-        self.assertEqual(len(entity.owned_by), 1) # make sure we have only one owner
-        self.assertEqual(entity.owned_by[0].eid, self.session.user.eid)
+        with self.admin_access.repo_cnx() as cnx:
+            entity = cnx.create_entity('Bookmark', title=u'wf1', path=u'/view')
+            cnx.commit() # fire operations
+            self.assertEqual(len(entity.owned_by), 1) # make sure we have only one owner
+            self.assertEqual(entity.owned_by[0].eid, self.session.user.eid)
 
     def test_user_login_stripped(self):
-        req = self.request()
-        u = self.create_user(req, '  joe  ')
-        tname = self.execute('Any L WHERE E login L, E eid %(e)s',
-                             {'e': u.eid})[0][0]
-        self.assertEqual(tname, 'joe')
-        self.execute('SET X login " jijoe " WHERE X eid %(x)s', {'x': u.eid})
-        tname = self.execute('Any L WHERE E login L, E eid %(e)s',
-                             {'e': u.eid})[0][0]
-        self.assertEqual(tname, 'jijoe')
+        with self.admin_access.repo_cnx() as cnx:
+            u = self.create_user(cnx, '  joe  ')
+            tname = cnx.execute('Any L WHERE E login L, E eid %(e)s',
+                                {'e': u.eid})[0][0]
+            self.assertEqual(tname, 'joe')
+            cnx.execute('SET X login " jijoe " WHERE X eid %(x)s', {'x': u.eid})
+            tname = cnx.execute('Any L WHERE E login L, E eid %(e)s',
+                                {'e': u.eid})[0][0]
+            self.assertEqual(tname, 'jijoe')
 
 
 
 class UserGroupHooksTC(CubicWebTC):
 
     def test_user_synchronization(self):
-        req = self.request()
-        self.create_user(req, 'toto', password='hop', commit=False)
-        self.assertRaises(AuthenticationError,
-                          self.repo.connect, u'toto', password='hop')
-        self.commit()
-        cnxid = self.repo.connect(u'toto', password='hop')
-        self.assertNotEqual(cnxid, self.session.id)
-        self.execute('DELETE CWUser X WHERE X login "toto"')
-        self.repo.execute(cnxid, 'State X')
-        self.commit()
-        self.assertRaises(BadConnectionId,
-                          self.repo.execute, cnxid, 'State X')
+        with self.admin_access.repo_cnx() as cnx:
+            self.create_user(cnx, 'toto', password='hop', commit=False)
+            self.assertRaises(AuthenticationError,
+                              self.repo.connect, u'toto', password='hop')
+            cnx.commit()
+            cnxid = self.repo.connect(u'toto', password='hop')
+            self.assertNotEqual(cnxid, self.session.id)
+            cnx.execute('DELETE CWUser X WHERE X login "toto"')
+            self.repo.execute(cnxid, 'State X')
+            cnx.commit()
+            self.assertRaises(BadConnectionId,
+                              self.repo.execute, cnxid, 'State X')
 
     def test_user_group_synchronization(self):
-        user = self.session.user
-        self.assertEqual(user.groups, set(('managers',)))
-        self.execute('SET X in_group G WHERE X eid %s, G name "guests"' % user.eid)
-        self.assertEqual(user.groups, set(('managers',)))
-        self.commit()
-        self.assertEqual(user.groups, set(('managers', 'guests')))
-        self.execute('DELETE X in_group G WHERE X eid %s, G name "guests"' % user.eid)
-        self.assertEqual(user.groups, set(('managers', 'guests')))
-        self.commit()
-        self.assertEqual(user.groups, set(('managers',)))
+        with self.admin_access.repo_cnx() as cnx:
+            user = cnx.user
+            self.assertEqual(user.groups, set(('managers',)))
+            cnx.execute('SET X in_group G WHERE X eid %s, G name "guests"' % user.eid)
+            self.assertEqual(user.groups, set(('managers',)))
+            cnx.commit()
+            self.assertEqual(user.groups, set(('managers', 'guests')))
+            cnx.execute('DELETE X in_group G WHERE X eid %s, G name "guests"' % user.eid)
+            self.assertEqual(user.groups, set(('managers', 'guests')))
+            cnx.commit()
+            self.assertEqual(user.groups, set(('managers',)))
 
     def test_user_composite_owner(self):
-        req = self.request()
-        ueid = self.create_user(req, 'toto').eid
-        # composite of euser should be owned by the euser regardless of who created it
-        self.execute('INSERT EmailAddress X: X address "toto@logilab.fr", U use_email X '
-                     'WHERE U login "toto"')
-        self.commit()
-        self.assertEqual(self.execute('Any A WHERE X owned_by U, U use_email X,'
-                                       'U login "toto", X address A')[0][0],
-                          'toto@logilab.fr')
+        with self.admin_access.repo_cnx() as cnx:
+            self.create_user(cnx, 'toto').eid
+            # composite of euser should be owned by the euser regardless of who created it
+            cnx.execute('INSERT EmailAddress X: X address "toto@logilab.fr", U use_email X '
+                         'WHERE U login "toto"')
+            cnx.commit()
+            self.assertEqual(cnx.execute('Any A WHERE X owned_by U, U use_email X,'
+                                           'U login "toto", X address A')[0][0],
+                              'toto@logilab.fr')
 
     def test_no_created_by_on_deleted_entity(self):
-        eid = self.execute('INSERT EmailAddress X: X address "toto@logilab.fr"')[0][0]
-        self.execute('DELETE EmailAddress X WHERE X eid %s' % eid)
-        self.commit()
-        self.assertFalse(self.execute('Any X WHERE X created_by Y, X eid >= %(x)s', {'x': eid}))
+        with self.admin_access.repo_cnx() as cnx:
+            eid = cnx.execute('INSERT EmailAddress X: X address "toto@logilab.fr"')[0][0]
+            cnx.execute('DELETE EmailAddress X WHERE X eid %s' % eid)
+            cnx.commit()
+            self.assertFalse(cnx.execute('Any X WHERE X created_by Y, X eid >= %(x)s', {'x': eid}))
 
 
 
 class SchemaHooksTC(CubicWebTC):
 
     def test_duplicate_etype_error(self):
-        # check we can't add a CWEType or CWRType entity if it already exists one
-        # with the same name
-        self.assertRaises(ValidationError,
-                          self.execute, 'INSERT CWEType X: X name "CWUser"')
-        self.assertRaises(ValidationError,
-                          self.execute, 'INSERT CWRType X: X name "in_group"')
+        with self.admin_access.repo_cnx() as cnx:
+            # check we can't add a CWEType or CWRType entity if it already exists one
+            # with the same name
+            self.assertRaises(ValidationError,
+                              cnx.execute, 'INSERT CWEType X: X name "CWUser"')
+            cnx.rollback()
+            self.assertRaises(ValidationError,
+                              cnx.execute, 'INSERT CWRType X: X name "in_group"')
 
     def test_validation_unique_constraint(self):
-        with self.assertRaises(ValidationError) as cm:
-            self.execute('INSERT CWUser X: X login "admin"')
-        ex = cm.exception
-        ex.translate(unicode)
-        self.assertIsInstance(ex.entity, int)
-        self.assertEqual(ex.errors, {'login-subject': 'the value "admin" is already used, use another one'})
+        with self.admin_access.repo_cnx() as cnx:
+            with self.assertRaises(ValidationError) as cm:
+                cnx.execute('INSERT CWUser X: X login "admin"')
+            ex = cm.exception
+            ex.translate(unicode)
+            self.assertIsInstance(ex.entity, int)
+            self.assertEqual(ex.errors, {'login-subject': 'the value "admin" is already used, use another one'})
 
 
 if __name__ == '__main__':
--- a/hooks/test/unittest_integrity.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/hooks/test/unittest_integrity.py	Fri Jul 18 17:35:25 2014 +0200
@@ -24,126 +24,138 @@
 class CoreHooksTC(CubicWebTC):
 
     def test_delete_internal_entities(self):
-        self.assertRaises(ValidationError, self.execute,
-                          'DELETE CWEType X WHERE X name "CWEType"')
-        self.assertRaises(ValidationError, self.execute,
-                          'DELETE CWRType X WHERE X name "relation_type"')
-        self.assertRaises(ValidationError, self.execute,
-                          'DELETE CWGroup X WHERE X name "owners"')
+        with self.admin_access.repo_cnx() as cnx:
+            self.assertRaises(ValidationError, cnx.execute,
+                              'DELETE CWEType X WHERE X name "CWEType"')
+            cnx.rollback()
+            self.assertRaises(ValidationError, cnx.execute,
+                              'DELETE CWRType X WHERE X name "relation_type"')
+            cnx.rollback()
+            self.assertRaises(ValidationError, cnx.execute,
+                              'DELETE CWGroup X WHERE X name "owners"')
 
     def test_delete_required_relations_subject(self):
-        self.execute('INSERT CWUser X: X login "toto", X upassword "hop", X in_group Y '
-                     'WHERE Y name "users"')
-        self.commit()
-        self.execute('DELETE X in_group Y WHERE X login "toto", Y name "users"')
-        self.assertRaises(ValidationError, self.commit)
-        self.execute('DELETE X in_group Y WHERE X login "toto"')
-        self.execute('SET X in_group Y WHERE X login "toto", Y name "guests"')
-        self.commit()
+        with self.admin_access.repo_cnx() as cnx:
+            cnx.execute('INSERT CWUser X: X login "toto", X upassword "hop", X in_group Y '
+                         'WHERE Y name "users"')
+            cnx.commit()
+            cnx.execute('DELETE X in_group Y WHERE X login "toto", Y name "users"')
+            self.assertRaises(ValidationError, cnx.commit)
+            cnx.rollback()
+            cnx.execute('DELETE X in_group Y WHERE X login "toto"')
+            cnx.execute('SET X in_group Y WHERE X login "toto", Y name "guests"')
+            cnx.commit()
 
     def test_static_vocabulary_check(self):
-        self.assertRaises(ValidationError,
-                          self.execute,
-                          'SET X composite "whatever" WHERE X from_entity FE, FE name "CWUser", X relation_type RT, RT name "in_group"')
+        with self.admin_access.repo_cnx() as cnx:
+            self.assertRaises(ValidationError,
+                              cnx.execute,
+                              'SET X composite "whatever" WHERE X from_entity FE, FE name "CWUser", '
+                              'X relation_type RT, RT name "in_group"')
 
     def test_missing_required_relations_subject_inline(self):
-        # missing in_group relation
-        self.execute('INSERT CWUser X: X login "toto", X upassword "hop"')
-        self.assertRaises(ValidationError,
-                          self.commit)
+        with self.admin_access.repo_cnx() as cnx:
+            # missing in_group relation
+            cnx.execute('INSERT CWUser X: X login "toto", X upassword "hop"')
+            self.assertRaises(ValidationError, cnx.commit)
 
     def test_composite_1(self):
-        self.execute('INSERT EmailAddress X: X address "toto@logilab.fr", X alias "hop"')
-        self.execute('INSERT EmailPart X: X content_format "text/plain", X ordernum 1, X content "this is a test"')
-        self.execute('INSERT Email X: X messageid "<1234>", X subject "test", X sender Y, X recipients Y, X parts P '
-                     'WHERE Y is EmailAddress, P is EmailPart')
-        self.assertTrue(self.execute('Email X WHERE X sender Y'))
-        self.commit()
-        self.execute('DELETE Email X')
-        rset = self.execute('Any X WHERE X is EmailPart')
-        self.assertEqual(len(rset), 0)
-        self.commit()
-        rset = self.execute('Any X WHERE X is EmailPart')
-        self.assertEqual(len(rset), 0)
+        with self.admin_access.repo_cnx() as cnx:
+            cnx.execute('INSERT EmailAddress X: X address "toto@logilab.fr", X alias "hop"')
+            cnx.execute('INSERT EmailPart X: X content_format "text/plain", X ordernum 1, '
+                        'X content "this is a test"')
+            cnx.execute('INSERT Email X: X messageid "<1234>", X subject "test", X sender Y, '
+                        'X recipients Y, X parts P '
+                         'WHERE Y is EmailAddress, P is EmailPart')
+            self.assertTrue(cnx.execute('Email X WHERE X sender Y'))
+            cnx.commit()
+            cnx.execute('DELETE Email X')
+            rset = cnx.execute('Any X WHERE X is EmailPart')
+            self.assertEqual(len(rset), 0)
+            cnx.commit()
+            rset = cnx.execute('Any X WHERE X is EmailPart')
+            self.assertEqual(len(rset), 0)
 
     def test_composite_2(self):
-        self.execute('INSERT EmailAddress X: X address "toto@logilab.fr", X alias "hop"')
-        self.execute('INSERT EmailPart X: X content_format "text/plain", X ordernum 1, X content "this is a test"')
-        self.execute('INSERT Email X: X messageid "<1234>", X subject "test", X sender Y, X recipients Y, X parts P '
-                     'WHERE Y is EmailAddress, P is EmailPart')
-        self.commit()
-        self.execute('DELETE Email X')
-        self.execute('DELETE EmailPart X')
-        self.commit()
-        rset = self.execute('Any X WHERE X is EmailPart')
-        self.assertEqual(len(rset), 0)
+        with self.admin_access.repo_cnx() as cnx:
+            cnx.execute('INSERT EmailAddress X: X address "toto@logilab.fr", X alias "hop"')
+            cnx.execute('INSERT EmailPart X: X content_format "text/plain", X ordernum 1, '
+                        'X content "this is a test"')
+            cnx.execute('INSERT Email X: X messageid "<1234>", X subject "test", X sender Y, '
+                        'X recipients Y, X parts P '
+                         'WHERE Y is EmailAddress, P is EmailPart')
+            cnx.commit()
+            cnx.execute('DELETE Email X')
+            cnx.execute('DELETE EmailPart X')
+            cnx.commit()
+            rset = cnx.execute('Any X WHERE X is EmailPart')
+            self.assertEqual(len(rset), 0)
 
     def test_composite_redirection(self):
-        self.execute('INSERT EmailAddress X: X address "toto@logilab.fr", X alias "hop"')
-        self.execute('INSERT EmailPart X: X content_format "text/plain", X ordernum 1, X content "this is a test"')
-        self.execute('INSERT Email X: X messageid "<1234>", X subject "test", X sender Y, X recipients Y, X parts P '
-                     'WHERE Y is EmailAddress, P is EmailPart')
-        self.execute('INSERT Email X: X messageid "<2345>", X subject "test2", X sender Y, X recipients Y '
-                     'WHERE Y is EmailAddress')
-        self.commit()
-        self.execute('DELETE X parts Y WHERE X messageid "<1234>"')
-        self.execute('SET X parts Y WHERE X messageid "<2345>"')
-        self.commit()
-        rset = self.execute('Any X WHERE X is EmailPart')
-        self.assertEqual(len(rset), 1)
-        self.assertEqual(rset.get_entity(0, 0).reverse_parts[0].messageid, '<2345>')
+        with self.admin_access.repo_cnx() as cnx:
+            cnx.execute('INSERT EmailAddress X: X address "toto@logilab.fr", X alias "hop"')
+            cnx.execute('INSERT EmailPart X: X content_format "text/plain", X ordernum 1, '
+                        'X content "this is a test"')
+            cnx.execute('INSERT Email X: X messageid "<1234>", X subject "test", X sender Y, '
+                        'X recipients Y, X parts P '
+                         'WHERE Y is EmailAddress, P is EmailPart')
+            cnx.execute('INSERT Email X: X messageid "<2345>", X subject "test2", X sender Y, '
+                        'X recipients Y '
+                         'WHERE Y is EmailAddress')
+            cnx.commit()
+            cnx.execute('DELETE X parts Y WHERE X messageid "<1234>"')
+            cnx.execute('SET X parts Y WHERE X messageid "<2345>"')
+            cnx.commit()
+            rset = cnx.execute('Any X WHERE X is EmailPart')
+            self.assertEqual(len(rset), 1)
+            self.assertEqual(rset.get_entity(0, 0).reverse_parts[0].messageid, '<2345>')
 
     def test_composite_object_relation_deletion(self):
-        req = self.request()
-        root = req.create_entity('Folder', name=u'root')
-        a = req.create_entity('Folder', name=u'a', parent=root)
-        b = req.create_entity('Folder', name=u'b', parent=a)
-        c = req.create_entity('Folder', name=u'c', parent=root)
-        self.commit()
-        req = self.request()
-        req.execute('DELETE Folder F WHERE F name "a"')
-        req.execute('DELETE F parent R WHERE R name "root"')
-        self.commit()
-        req = self.request()
-        self.assertEqual([['root'], ['c']],
-                         req.execute('Any NF WHERE F is Folder, F name NF').rows)
-        self.assertEqual([],
-                         req.execute('Any NF,NP WHERE F parent P, F name NF, P name NP').rows)
+        with self.admin_access.repo_cnx() as cnx:
+            root = cnx.create_entity('Folder', name=u'root')
+            a = cnx.create_entity('Folder', name=u'a', parent=root)
+            cnx.create_entity('Folder', name=u'b', parent=a)
+            cnx.create_entity('Folder', name=u'c', parent=root)
+            cnx.commit()
+            cnx.execute('DELETE Folder F WHERE F name "a"')
+            cnx.execute('DELETE F parent R WHERE R name "root"')
+            cnx.commit()
+            self.assertEqual([['root'], ['c']],
+                             cnx.execute('Any NF WHERE F is Folder, F name NF').rows)
+            self.assertEqual([], cnx.execute('Any NF,NP WHERE F parent P, F name NF, P name NP').rows)
 
     def test_composite_subject_relation_deletion(self):
-        req = self.request()
-        root = req.create_entity('Folder', name=u'root')
-        a = req.create_entity('Folder', name=u'a')
-        b = req.create_entity('Folder', name=u'b')
-        c = req.create_entity('Folder', name=u'c')
-        root.cw_set(children=(a, c))
-        a.cw_set(children=b)
-        self.commit()
-        req = self.request()
-        req.execute('DELETE Folder F WHERE F name "a"')
-        req.execute('DELETE R children F WHERE R name "root"')
-        self.commit()
-        req = self.request()
-        self.assertEqual([['root'], ['c']],
-                         req.execute('Any NF WHERE F is Folder, F name NF').rows)
-        self.assertEqual([],
-                         req.execute('Any NF,NP WHERE F parent P, F name NF, P name NP').rows)
+        with self.admin_access.repo_cnx() as cnx:
+            root = cnx.create_entity('Folder', name=u'root')
+            a = cnx.create_entity('Folder', name=u'a')
+            b = cnx.create_entity('Folder', name=u'b')
+            c = cnx.create_entity('Folder', name=u'c')
+            root.cw_set(children=(a, c))
+            a.cw_set(children=b)
+            cnx.commit()
+            cnx.execute('DELETE Folder F WHERE F name "a"')
+            cnx.execute('DELETE R children F WHERE R name "root"')
+            cnx.commit()
+            self.assertEqual([['root'], ['c']],
+                             cnx.execute('Any NF WHERE F is Folder, F name NF').rows)
+            self.assertEqual([], cnx.execute('Any NF,NP WHERE F parent P, F name NF, P name NP').rows)
 
     def test_unsatisfied_constraints(self):
-        releid = self.execute('SET U in_group G WHERE G name "owners", U login "admin"')[0][0]
-        with self.assertRaises(ValidationError) as cm:
-            self.commit()
+        with self.admin_access.repo_cnx() as cnx:
+            cnx.execute('SET U in_group G WHERE G name "owners", U login "admin"')[0][0]
+            with self.assertRaises(ValidationError) as cm:
+                cnx.commit()
         self.assertEqual(cm.exception.errors,
-                          {'in_group-object': u'RQLConstraint NOT O name "owners" failed'})
+                         {'in_group-object': u'RQLConstraint NOT O name "owners" failed'})
 
     def test_unique_constraint(self):
-        req = self.request()
-        entity = req.create_entity('CWGroup', name=u'trout')
-        self.commit()
-        self.assertRaises(ValidationError, req.create_entity, 'CWGroup', name=u'trout')
-        self.rollback()
-        req.execute('SET X name "trout" WHERE X eid %(x)s', {'x': entity.eid})
-        self.commit()
+        with self.admin_access.repo_cnx() as cnx:
+            entity = cnx.create_entity('CWGroup', name=u'trout')
+            cnx.commit()
+            self.assertRaises(ValidationError, cnx.create_entity, 'CWGroup', name=u'trout')
+            cnx.rollback()
+            cnx.execute('SET X name "trout" WHERE X eid %(x)s', {'x': entity.eid})
+            cnx.commit()
 
 if __name__ == '__main__':
     from logilab.common.testlib import unittest_main
--- a/hooks/test/unittest_syncschema.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/hooks/test/unittest_syncschema.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -17,13 +17,13 @@
 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
 """cubicweb.server.hooks.syncschema unit and functional tests"""
 
-from logilab.common.testlib import TestCase, unittest_main
+from logilab.common.testlib import unittest_main
 
 from cubicweb import ValidationError, Binary
 from cubicweb.schema import META_RTYPES
 from cubicweb.devtools.testlib import CubicWebTC
 from cubicweb.server.sqlutils import SQL_PREFIX
-from cubicweb.devtools.repotest import schema_eids_idx, restore_schema_eids_idx
+from cubicweb.devtools.repotest import schema_eids_idx
 
 
 def tearDownModule(*args):
@@ -36,320 +36,343 @@
         self.repo.set_schema(self.repo.deserialize_schema(), resetvreg=False)
         self.__class__.schema_eids = schema_eids_idx(self.repo.schema)
 
-    def index_exists(self, etype, attr, unique=False):
-        self.session.set_cnxset()
+    def index_exists(self, cnx, etype, attr, unique=False):
         dbhelper = self.repo.system_source.dbhelper
-        sqlcursor = self.session.cnxset.cu
-        return dbhelper.index_exists(sqlcursor, SQL_PREFIX + etype, SQL_PREFIX + attr, unique=unique)
+        with cnx.ensure_cnx_set:
+            sqlcursor = cnx.cnxset.cu
+            return dbhelper.index_exists(sqlcursor,
+                                         SQL_PREFIX + etype,
+                                         SQL_PREFIX + attr,
+                                         unique=unique)
 
-    def _set_perms(self, eid):
-        self.execute('SET X read_permission G WHERE X eid %(x)s, G is CWGroup',
-                     {'x': eid})
-        self.execute('SET X add_permission G WHERE X eid %(x)s, G is CWGroup, G name "managers"',
-                     {'x': eid})
-        self.execute('SET X delete_permission G WHERE X eid %(x)s, G is CWGroup, G name "owners"',
-                     {'x': eid})
+    def _set_perms(self, cnx, eid):
+        cnx.execute('SET X read_permission G WHERE X eid %(x)s, G is CWGroup',
+                    {'x': eid})
+        cnx.execute('SET X add_permission G WHERE X eid %(x)s, G is CWGroup, '
+                    'G name "managers"', {'x': eid})
+        cnx.execute('SET X delete_permission G WHERE X eid %(x)s, G is CWGroup, '
+                    'G name "owners"', {'x': eid})
 
-    def _set_attr_perms(self, eid):
-        self.execute('SET X read_permission G WHERE X eid %(x)s, G is CWGroup',
-                     {'x': eid})
-        self.execute('SET X update_permission G WHERE X eid %(x)s, G is CWGroup, G name "managers"',
-                     {'x': eid})
+    def _set_attr_perms(self, cnx, eid):
+        cnx.execute('SET X read_permission G WHERE X eid %(x)s, G is CWGroup',
+                    {'x': eid})
+        cnx.execute('SET X update_permission G WHERE X eid %(x)s, G is CWGroup, G name "managers"',
+                    {'x': eid})
 
     def test_base(self):
-        schema = self.repo.schema
-        self.session.set_cnxset()
-        dbhelper = self.repo.system_source.dbhelper
-        sqlcursor = self.session.cnxset.cu
-        self.assertFalse(schema.has_entity('Societe2'))
-        self.assertFalse(schema.has_entity('concerne2'))
-        # schema should be update on insertion (after commit)
-        eeid = self.execute('INSERT CWEType X: X name "Societe2", X description "", X final FALSE')[0][0]
-        self._set_perms(eeid)
-        self.execute('INSERT CWRType X: X name "concerne2", X description "", X final FALSE, X symmetric FALSE')
-        self.assertFalse(schema.has_entity('Societe2'))
-        self.assertFalse(schema.has_entity('concerne2'))
-        # have to commit before adding definition relations
-        self.commit()
-        self.assertTrue(schema.has_entity('Societe2'))
-        self.assertTrue(schema.has_relation('concerne2'))
-        attreid = self.execute('INSERT CWAttribute X: X cardinality "11", X defaultval %(default)s, '
-                               '   X indexed TRUE, X relation_type RT, X from_entity E, X to_entity F '
-                               'WHERE RT name "name", E name "Societe2", F name "String"',
-                               {'default': Binary.zpickle('noname')})[0][0]
-        self._set_attr_perms(attreid)
-        concerne2_rdef_eid = self.execute(
-            'INSERT CWRelation X: X cardinality "**", X relation_type RT, X from_entity E, X to_entity E '
-            'WHERE RT name "concerne2", E name "Societe2"')[0][0]
-        self._set_perms(concerne2_rdef_eid)
-        self.assertNotIn('name', schema['Societe2'].subject_relations())
-        self.assertNotIn('concerne2', schema['Societe2'].subject_relations())
-        self.assertFalse(self.index_exists('Societe2', 'name'))
-        self.commit()
-        self.assertIn('name', schema['Societe2'].subject_relations())
-        self.assertIn('concerne2', schema['Societe2'].subject_relations())
-        self.assertTrue(self.index_exists('Societe2', 'name'))
-        # now we should be able to insert and query Societe2
-        s2eid = self.execute('INSERT Societe2 X: X name "logilab"')[0][0]
-        self.execute('Societe2 X WHERE X name "logilab"')
-        self.execute('SET X concerne2 X WHERE X name "logilab"')
-        rset = self.execute('Any X WHERE X concerne2 Y')
-        self.assertEqual(rset.rows, [[s2eid]])
-        # check that when a relation definition is deleted, existing relations are deleted
-        rdefeid = self.execute('INSERT CWRelation X: X cardinality "**", X relation_type RT, '
-                               '   X from_entity E, X to_entity E '
-                               'WHERE RT name "concerne2", E name "CWUser"')[0][0]
-        self._set_perms(rdefeid)
-        self.commit()
-        self.execute('DELETE CWRelation X WHERE X eid %(x)s', {'x': concerne2_rdef_eid})
-        self.commit()
-        self.assertIn('concerne2', schema['CWUser'].subject_relations())
-        self.assertNotIn('concerne2', schema['Societe2'].subject_relations())
-        self.assertFalse(self.execute('Any X WHERE X concerne2 Y'))
-        # schema should be cleaned on delete (after commit)
-        self.execute('DELETE CWEType X WHERE X name "Societe2"')
-        self.execute('DELETE CWRType X WHERE X name "concerne2"')
-        self.assertTrue(self.index_exists('Societe2', 'name'))
-        self.assertTrue(schema.has_entity('Societe2'))
-        self.assertTrue(schema.has_relation('concerne2'))
-        self.commit()
-        self.assertFalse(self.index_exists('Societe2', 'name'))
-        self.assertFalse(schema.has_entity('Societe2'))
-        self.assertFalse(schema.has_entity('concerne2'))
-        self.assertNotIn('concerne2', schema['CWUser'].subject_relations())
+        with self.admin_access.repo_cnx() as cnx:
+            schema = self.repo.schema
+            self.assertFalse(schema.has_entity('Societe2'))
+            self.assertFalse(schema.has_entity('concerne2'))
+            # schema should be update on insertion (after commit)
+            eeid = cnx.execute('INSERT CWEType X: X name "Societe2", '
+                               'X description "", X final FALSE')[0][0]
+            self._set_perms(cnx, eeid)
+            cnx.execute('INSERT CWRType X: X name "concerne2", X description "", '
+                        'X final FALSE, X symmetric FALSE')
+            self.assertFalse(schema.has_entity('Societe2'))
+            self.assertFalse(schema.has_entity('concerne2'))
+            # have to commit before adding definition relations
+            cnx.commit()
+            self.assertTrue(schema.has_entity('Societe2'))
+            self.assertTrue(schema.has_relation('concerne2'))
+            attreid = cnx.execute('INSERT CWAttribute X: X cardinality "11", '
+                                  'X defaultval %(default)s, X indexed TRUE, '
+                                  'X relation_type RT, X from_entity E, X to_entity F '
+                                   'WHERE RT name "name", E name "Societe2", '
+                                  'F name "String"',
+                                   {'default': Binary.zpickle('noname')})[0][0]
+            self._set_attr_perms(cnx, attreid)
+            concerne2_rdef_eid = cnx.execute(
+                'INSERT CWRelation X: X cardinality "**", X relation_type RT, '
+                'X from_entity E, X to_entity E '
+                'WHERE RT name "concerne2", E name "Societe2"')[0][0]
+            self._set_perms(cnx, concerne2_rdef_eid)
+            self.assertNotIn('name', schema['Societe2'].subject_relations())
+            self.assertNotIn('concerne2', schema['Societe2'].subject_relations())
+            self.assertFalse(self.index_exists(cnx, 'Societe2', 'name'))
+            cnx.commit()
+            self.assertIn('name', schema['Societe2'].subject_relations())
+            self.assertIn('concerne2', schema['Societe2'].subject_relations())
+            self.assertTrue(self.index_exists(cnx, 'Societe2', 'name'))
+            # now we should be able to insert and query Societe2
+            s2eid = cnx.execute('INSERT Societe2 X: X name "logilab"')[0][0]
+            cnx.execute('Societe2 X WHERE X name "logilab"')
+            cnx.execute('SET X concerne2 X WHERE X name "logilab"')
+            rset = cnx.execute('Any X WHERE X concerne2 Y')
+            self.assertEqual(rset.rows, [[s2eid]])
+            # check that when a relation definition is deleted, existing relations are deleted
+            rdefeid = cnx.execute('INSERT CWRelation X: X cardinality "**", X relation_type RT, '
+                                   '   X from_entity E, X to_entity E '
+                                   'WHERE RT name "concerne2", E name "CWUser"')[0][0]
+            self._set_perms(cnx, rdefeid)
+            cnx.commit()
+            cnx.execute('DELETE CWRelation X WHERE X eid %(x)s', {'x': concerne2_rdef_eid})
+            cnx.commit()
+            self.assertIn('concerne2', schema['CWUser'].subject_relations())
+            self.assertNotIn('concerne2', schema['Societe2'].subject_relations())
+            self.assertFalse(cnx.execute('Any X WHERE X concerne2 Y'))
+            # schema should be cleaned on delete (after commit)
+            cnx.execute('DELETE CWEType X WHERE X name "Societe2"')
+            cnx.execute('DELETE CWRType X WHERE X name "concerne2"')
+            self.assertTrue(self.index_exists(cnx, 'Societe2', 'name'))
+            self.assertTrue(schema.has_entity('Societe2'))
+            self.assertTrue(schema.has_relation('concerne2'))
+            cnx.commit()
+            self.assertFalse(self.index_exists(cnx, 'Societe2', 'name'))
+            self.assertFalse(schema.has_entity('Societe2'))
+            self.assertFalse(schema.has_entity('concerne2'))
+            self.assertNotIn('concerne2', schema['CWUser'].subject_relations())
 
     def test_metartype_with_nordefs(self):
-        META_RTYPES.add('custom_meta')
-        self.execute('INSERT CWRType X: X name "custom_meta", X description "", '
-                     'X final FALSE, X symmetric FALSE')
-        self.commit()
-        eeid = self.execute('INSERT CWEType X: X name "NEWEtype", '
-                            'X description "", X final FALSE')[0][0]
-        self._set_perms(eeid)
-        self.commit()
-        META_RTYPES.remove('custom_meta')
+        with self.admin_access.repo_cnx() as cnx:
+            META_RTYPES.add('custom_meta')
+            cnx.execute('INSERT CWRType X: X name "custom_meta", X description "", '
+                         'X final FALSE, X symmetric FALSE')
+            cnx.commit()
+            eeid = cnx.execute('INSERT CWEType X: X name "NEWEtype", '
+                                'X description "", X final FALSE')[0][0]
+            self._set_perms(cnx, eeid)
+            cnx.commit()
+            META_RTYPES.remove('custom_meta')
 
     def test_metartype_with_somerdefs(self):
-        META_RTYPES.add('custom_meta')
-        self.execute('INSERT CWRType X: X name "custom_meta", X description "", '
-                     'X final FALSE, X symmetric FALSE')
-        self.commit()
-        rdefeid = self.execute('INSERT CWRelation X: X cardinality "**", X relation_type RT, '
-                               '   X from_entity E, X to_entity E '
-                               'WHERE RT name "custom_meta", E name "CWUser"')[0][0]
-        self._set_perms(rdefeid)
-        self.commit()
-        eeid = self.execute('INSERT CWEType X: X name "NEWEtype", '
-                            'X description "", X final FALSE')[0][0]
-        self._set_perms(eeid)
-        self.commit()
-        META_RTYPES.remove('custom_meta')
+        with self.admin_access.repo_cnx() as cnx:
+            META_RTYPES.add('custom_meta')
+            cnx.execute('INSERT CWRType X: X name "custom_meta", X description "", '
+                         'X final FALSE, X symmetric FALSE')
+            cnx.commit()
+            rdefeid = cnx.execute('INSERT CWRelation X: X cardinality "**", X relation_type RT, '
+                                   '   X from_entity E, X to_entity E '
+                                   'WHERE RT name "custom_meta", E name "CWUser"')[0][0]
+            self._set_perms(cnx, rdefeid)
+            cnx.commit()
+            eeid = cnx.execute('INSERT CWEType X: X name "NEWEtype", '
+                                'X description "", X final FALSE')[0][0]
+            self._set_perms(cnx, eeid)
+            cnx.commit()
+            META_RTYPES.remove('custom_meta')
 
     def test_is_instance_of_insertions(self):
-        seid = self.execute('INSERT Transition T: T name "subdiv"')[0][0]
-        is_etypes = [etype for etype, in self.execute('Any ETN WHERE X eid %s, X is ET, ET name ETN' % seid)]
-        self.assertEqual(is_etypes, ['Transition'])
-        instanceof_etypes = [etype for etype, in self.execute('Any ETN WHERE X eid %s, X is_instance_of ET, ET name ETN' % seid)]
-        self.assertEqual(sorted(instanceof_etypes), ['BaseTransition', 'Transition'])
-        snames = [name for name, in self.execute('Any N WHERE S is BaseTransition, S name N')]
-        self.assertNotIn('subdiv', snames)
-        snames = [name for name, in self.execute('Any N WHERE S is_instance_of BaseTransition, S name N')]
-        self.assertIn('subdiv', snames)
+        with self.admin_access.repo_cnx() as cnx:
+            seid = cnx.execute('INSERT Transition T: T name "subdiv"')[0][0]
+            is_etypes = [etype for etype, in cnx.execute('Any ETN WHERE X eid %s, '
+                                                         'X is ET, ET name ETN' % seid)]
+            self.assertEqual(is_etypes, ['Transition'])
+            instanceof_etypes = [etype
+                                 for etype, in cnx.execute('Any ETN WHERE X eid %s, '
+                                                           'X is_instance_of ET, ET name ETN'
+                                                           % seid)]
+            self.assertEqual(sorted(instanceof_etypes), ['BaseTransition', 'Transition'])
+            snames = [name for name, in cnx.execute('Any N WHERE S is BaseTransition, S name N')]
+            self.assertNotIn('subdiv', snames)
+            snames = [name for name, in cnx.execute('Any N WHERE S is_instance_of BaseTransition, '
+                                                    'S name N')]
+            self.assertIn('subdiv', snames)
 
 
     def test_perms_synchronization_1(self):
-        schema = self.repo.schema
-        self.assertEqual(schema['CWUser'].get_groups('read'), set(('managers', 'users')))
-        self.assertTrue(self.execute('Any X, Y WHERE X is CWEType, X name "CWUser", Y is CWGroup, Y name "users"')[0])
-        self.execute('DELETE X read_permission Y WHERE X is CWEType, X name "CWUser", Y name "users"')
-        self.assertEqual(schema['CWUser'].get_groups('read'), set(('managers', 'users', )))
-        self.commit()
-        self.assertEqual(schema['CWUser'].get_groups('read'), set(('managers',)))
-        self.execute('SET X read_permission Y WHERE X is CWEType, X name "CWUser", Y name "users"')
-        self.commit()
-        self.assertEqual(schema['CWUser'].get_groups('read'), set(('managers', 'users',)))
+        with self.admin_access.repo_cnx() as cnx:
+            schema = self.repo.schema
+            self.assertEqual(schema['CWUser'].get_groups('read'), set(('managers', 'users')))
+            self.assertTrue(cnx.execute('Any X, Y WHERE X is CWEType, X name "CWUser", '
+                                        'Y is CWGroup, Y name "users"')[0])
+            cnx.execute('DELETE X read_permission Y WHERE X is CWEType, X name "CWUser", Y name "users"')
+            self.assertEqual(schema['CWUser'].get_groups('read'), set(('managers', 'users', )))
+            cnx.commit()
+            self.assertEqual(schema['CWUser'].get_groups('read'), set(('managers',)))
+            cnx.execute('SET X read_permission Y WHERE X is CWEType, '
+                        'X name "CWUser", Y name "users"')
+            cnx.commit()
+            self.assertEqual(schema['CWUser'].get_groups('read'),
+                             set(('managers', 'users',)))
 
     def test_perms_synchronization_2(self):
-        schema = self.repo.schema['in_group'].rdefs[('CWUser', 'CWGroup')]
-        self.assertEqual(schema.get_groups('read'), set(('managers', 'users', 'guests')))
-        self.execute('DELETE X read_permission Y WHERE X relation_type RT, RT name "in_group", Y name "guests"')
-        self.assertEqual(schema.get_groups('read'), set(('managers', 'users', 'guests')))
-        self.commit()
-        self.assertEqual(schema.get_groups('read'), set(('managers', 'users')))
-        self.execute('SET X read_permission Y WHERE X relation_type RT, RT name "in_group", Y name "guests"')
-        self.assertEqual(schema.get_groups('read'), set(('managers', 'users')))
-        self.commit()
-        self.assertEqual(schema.get_groups('read'), set(('managers', 'users', 'guests')))
+        with self.admin_access.repo_cnx() as cnx:
+            schema = self.repo.schema['in_group'].rdefs[('CWUser', 'CWGroup')]
+            self.assertEqual(schema.get_groups('read'),
+                             set(('managers', 'users', 'guests')))
+            cnx.execute('DELETE X read_permission Y WHERE X relation_type RT, '
+                        'RT name "in_group", Y name "guests"')
+            self.assertEqual(schema.get_groups('read'),
+                             set(('managers', 'users', 'guests')))
+            cnx.commit()
+            self.assertEqual(schema.get_groups('read'),
+                             set(('managers', 'users')))
+            cnx.execute('SET X read_permission Y WHERE X relation_type RT, '
+                        'RT name "in_group", Y name "guests"')
+            self.assertEqual(schema.get_groups('read'),
+                             set(('managers', 'users')))
+            cnx.commit()
+            self.assertEqual(schema.get_groups('read'),
+                             set(('managers', 'users', 'guests')))
 
     def test_nonregr_user_edit_itself(self):
-        ueid = self.session.user.eid
-        groupeids = [eid for eid, in self.execute('CWGroup G WHERE G name in ("managers", "users")')]
-        self.execute('DELETE X in_group Y WHERE X eid %s' % ueid)
-        self.execute('SET X surname "toto" WHERE X eid %s' % ueid)
-        self.execute('SET X in_group Y WHERE X eid %s, Y name "managers"' % ueid)
-        self.commit()
-        eeid = self.execute('Any X WHERE X is CWEType, X name "CWEType"')[0][0]
-        self.execute('DELETE X read_permission Y WHERE X eid %s' % eeid)
-        self.execute('SET X final FALSE WHERE X eid %s' % eeid)
-        self.execute('SET X read_permission Y WHERE X eid %s, Y eid in (%s, %s)'
-                     % (eeid, groupeids[0], groupeids[1]))
-        self.commit()
-        self.execute('Any X WHERE X is CWEType, X name "CWEType"')
+        with self.admin_access.repo_cnx() as cnx:
+            ueid = cnx.user.eid
+            groupeids = [eid for eid, in cnx.execute('CWGroup G WHERE G name '
+                                                     'in ("managers", "users")')]
+            cnx.execute('DELETE X in_group Y WHERE X eid %s' % ueid)
+            cnx.execute('SET X surname "toto" WHERE X eid %s' % ueid)
+            cnx.execute('SET X in_group Y WHERE X eid %s, Y name "managers"' % ueid)
+            cnx.commit()
+            eeid = cnx.execute('Any X WHERE X is CWEType, X name "CWEType"')[0][0]
+            cnx.execute('DELETE X read_permission Y WHERE X eid %s' % eeid)
+            cnx.execute('SET X final FALSE WHERE X eid %s' % eeid)
+            cnx.execute('SET X read_permission Y WHERE X eid %s, Y eid in (%s, %s)'
+                         % (eeid, groupeids[0], groupeids[1]))
+            cnx.commit()
+            cnx.execute('Any X WHERE X is CWEType, X name "CWEType"')
 
     # schema modification hooks tests #########################################
 
     def test_uninline_relation(self):
-        self.session.set_cnxset()
-        dbhelper = self.repo.system_source.dbhelper
-        sqlcursor = self.session.cnxset.cu
-        self.assertTrue(self.schema['state_of'].inlined)
-        try:
-            self.execute('SET X inlined FALSE WHERE X name "state_of"')
-            self.assertTrue(self.schema['state_of'].inlined)
-            self.commit()
-            self.assertFalse(self.schema['state_of'].inlined)
-            self.assertFalse(self.index_exists('State', 'state_of'))
-            rset = self.execute('Any X, Y WHERE X state_of Y')
-            self.assertEqual(len(rset), 2) # user states
-        except Exception:
-            import traceback
-            traceback.print_exc()
-        finally:
-            self.execute('SET X inlined TRUE WHERE X name "state_of"')
-            self.assertFalse(self.schema['state_of'].inlined)
-            self.commit()
-            self.assertTrue(self.schema['state_of'].inlined)
-            self.assertTrue(self.index_exists('State', 'state_of'))
-            rset = self.execute('Any X, Y WHERE X state_of Y')
-            self.assertEqual(len(rset), 2)
+        with self.admin_access.repo_cnx() as cnx:
+            try:
+                self.assertTrue(self.schema['state_of'].inlined)
+                cnx.execute('SET X inlined FALSE WHERE X name "state_of"')
+                self.assertTrue(self.schema['state_of'].inlined)
+                cnx.commit()
+                self.assertFalse(self.schema['state_of'].inlined)
+                self.assertFalse(self.index_exists(cnx, 'State', 'state_of'))
+                rset = cnx.execute('Any X, Y WHERE X state_of Y')
+                self.assertEqual(len(rset), 2) # user states
+            finally:
+                cnx.execute('SET X inlined TRUE WHERE X name "state_of"')
+                self.assertFalse(self.schema['state_of'].inlined)
+                cnx.commit()
+                self.assertTrue(self.schema['state_of'].inlined)
+                self.assertTrue(self.index_exists(cnx, 'State', 'state_of'))
+                rset = cnx.execute('Any X, Y WHERE X state_of Y')
+                self.assertEqual(len(rset), 2)
 
     def test_indexed_change(self):
-        self.session.set_cnxset()
-        dbhelper = self.repo.system_source.dbhelper
-        sqlcursor = self.session.cnxset.cu
-        try:
-            self.execute('SET X indexed FALSE WHERE X relation_type R, R name "name"')
-            self.assertTrue(self.schema['name'].rdef('Workflow', 'String').indexed)
-            self.assertTrue(self.index_exists('Workflow', 'name'))
-            self.commit()
-            self.assertFalse(self.schema['name'].rdef('Workflow', 'String').indexed)
-            self.assertFalse(self.index_exists('Workflow', 'name'))
-        finally:
-            self.execute('SET X indexed TRUE WHERE X relation_type R, R name "name"')
-            self.assertFalse(self.schema['name'].rdef('Workflow', 'String').indexed)
-            self.assertFalse(self.index_exists('Workflow', 'name'))
-            self.commit()
-            self.assertTrue(self.schema['name'].rdef('Workflow', 'String').indexed)
-            self.assertTrue(self.index_exists('Workflow', 'name'))
+        with self.admin_access.repo_cnx() as cnx:
+            try:
+                cnx.execute('SET X indexed FALSE WHERE X relation_type R, R name "name"')
+                self.assertTrue(self.schema['name'].rdef('Workflow', 'String').indexed)
+                self.assertTrue(self.index_exists(cnx, 'Workflow', 'name'))
+                cnx.commit()
+                self.assertFalse(self.schema['name'].rdef('Workflow', 'String').indexed)
+                self.assertFalse(self.index_exists(cnx, 'Workflow', 'name'))
+            finally:
+                cnx.execute('SET X indexed TRUE WHERE X relation_type R, R name "name"')
+                self.assertFalse(self.schema['name'].rdef('Workflow', 'String').indexed)
+                self.assertFalse(self.index_exists(cnx, 'Workflow', 'name'))
+                cnx.commit()
+                self.assertTrue(self.schema['name'].rdef('Workflow', 'String').indexed)
+                self.assertTrue(self.index_exists(cnx, 'Workflow', 'name'))
 
     def test_unique_change(self):
-        self.session.set_cnxset()
-        dbhelper = self.repo.system_source.dbhelper
-        sqlcursor = self.session.cnxset.cu
-        try:
-            eid = self.execute('INSERT CWConstraint X: X cstrtype CT, DEF constrained_by X '
-                               'WHERE CT name "UniqueConstraint", DEF relation_type RT, DEF from_entity E,'
-                               'RT name "name", E name "Workflow"').rows[0][0]
-            self.assertFalse(self.schema['Workflow'].has_unique_values('name'))
-            self.assertFalse(self.index_exists('Workflow', 'name', unique=True))
-            self.commit()
-            self.assertTrue(self.schema['Workflow'].has_unique_values('name'))
-            self.assertTrue(self.index_exists('Workflow', 'name', unique=True))
-        finally:
-            self.execute('DELETE CWConstraint C WHERE C eid %(eid)s', {'eid': eid})
-            self.commit()
-            self.assertFalse(self.schema['Workflow'].has_unique_values('name'))
-            self.assertFalse(self.index_exists('Workflow', 'name', unique=True))
+        with self.admin_access.repo_cnx() as cnx:
+            try:
+                eid = cnx.execute('INSERT CWConstraint X: X cstrtype CT, DEF constrained_by X '
+                                  'WHERE CT name "UniqueConstraint", DEF relation_type RT, '
+                                  'DEF from_entity E, RT name "name", '
+                                  'E name "Workflow"').rows[0][0]
+                self.assertFalse(self.schema['Workflow'].has_unique_values('name'))
+                self.assertFalse(self.index_exists(cnx, 'Workflow', 'name', unique=True))
+                cnx.commit()
+                self.assertTrue(self.schema['Workflow'].has_unique_values('name'))
+                self.assertTrue(self.index_exists(cnx, 'Workflow', 'name', unique=True))
+            finally:
+                cnx.execute('DELETE CWConstraint C WHERE C eid %(eid)s', {'eid': eid})
+                cnx.commit()
+                self.assertFalse(self.schema['Workflow'].has_unique_values('name'))
+                self.assertFalse(self.index_exists(cnx, 'Workflow', 'name', unique=True))
 
     def test_required_change_1(self):
-        self.execute('SET DEF cardinality "?1" '
-                     'WHERE DEF relation_type RT, DEF from_entity E,'
-                     'RT name "title", E name "Bookmark"')
-        self.commit()
-        # should now be able to add bookmark without title
-        self.execute('INSERT Bookmark X: X path "/view"')
-        self.commit()
+        with self.admin_access.repo_cnx() as cnx:
+            cnx.execute('SET DEF cardinality "?1" '
+                         'WHERE DEF relation_type RT, DEF from_entity E,'
+                         'RT name "title", E name "Bookmark"')
+            cnx.commit()
+            # should now be able to add bookmark without title
+            cnx.execute('INSERT Bookmark X: X path "/view"')
+            cnx.commit()
 
     def test_required_change_2(self):
-        self.execute('SET DEF cardinality "11" '
-                     'WHERE DEF relation_type RT, DEF from_entity E,'
-                     'RT name "surname", E name "CWUser"')
-        self.commit()
-        # should not be able anymore to add cwuser without surname
-        req = self.request()
-        self.assertRaises(ValidationError, self.create_user, req, "toto")
-        self.rollback()
-        self.execute('SET DEF cardinality "?1" '
-                     'WHERE DEF relation_type RT, DEF from_entity E,'
-                     'RT name "surname", E name "CWUser"')
-        self.commit()
-
+        with self.admin_access.repo_cnx() as cnx:
+            cnx.execute('SET DEF cardinality "11" '
+                         'WHERE DEF relation_type RT, DEF from_entity E,'
+                         'RT name "surname", E name "CWUser"')
+            cnx.commit()
+            # should not be able anymore to add cwuser without surname
+            self.assertRaises(ValidationError, self.create_user, cnx, "toto")
+            cnx.rollback()
+            cnx.execute('SET DEF cardinality "?1" '
+                         'WHERE DEF relation_type RT, DEF from_entity E,'
+                         'RT name "surname", E name "CWUser"')
+            cnx.commit()
 
     def test_add_attribute_to_base_class(self):
-        attreid = self.execute('INSERT CWAttribute X: X cardinality "11", X defaultval %(default)s, '
-                               'X indexed TRUE, X relation_type RT, X from_entity E, X to_entity F '
-                               'WHERE RT name "messageid", E name "BaseTransition", F name "String"',
-                               {'default': Binary.zpickle('noname')})[0][0]
-        assert self.execute('SET X read_permission Y WHERE X eid %(x)s, Y name "managers"',
-                     {'x': attreid})
-        self.commit()
-        self.schema.rebuild_infered_relations()
-        self.assertIn('Transition', self.schema['messageid'].subjects())
-        self.assertIn('WorkflowTransition', self.schema['messageid'].subjects())
-        self.execute('Any X WHERE X is_instance_of BaseTransition, X messageid "hop"')
+        with self.admin_access.repo_cnx() as cnx:
+            attreid = cnx.execute('INSERT CWAttribute X: X cardinality "11", X defaultval %(default)s, '
+                                   'X indexed TRUE, X relation_type RT, X from_entity E, X to_entity F '
+                                   'WHERE RT name "messageid", E name "BaseTransition", F name "String"',
+                                   {'default': Binary.zpickle('noname')})[0][0]
+            assert cnx.execute('SET X read_permission Y WHERE X eid %(x)s, Y name "managers"',
+                               {'x': attreid})
+            cnx.commit()
+            self.schema.rebuild_infered_relations()
+            self.assertIn('Transition', self.schema['messageid'].subjects())
+            self.assertIn('WorkflowTransition', self.schema['messageid'].subjects())
+            cnx.execute('Any X WHERE X is_instance_of BaseTransition, X messageid "hop"')
 
     def test_change_fulltextindexed(self):
-        req = self.request()
-        target = req.create_entity(u'Email', messageid=u'1234',
-                                   subject=u'rick.roll@dance.com')
-        self.commit()
-        rset = req.execute('Any X WHERE X has_text "rick.roll"')
-        self.assertIn(target.eid, [item[0] for item in rset])
-        assert req.execute('SET A fulltextindexed FALSE '
-                            'WHERE E is CWEType, E name "Email", A is CWAttribute,'
-                            'A from_entity E, A relation_type R, R name "subject"')
-        self.commit()
-        rset = req.execute('Any X WHERE X has_text "rick.roll"')
-        self.assertFalse(rset)
-        assert req.execute('SET A fulltextindexed TRUE '
-                           'WHERE A from_entity E, A relation_type R, '
-                           'E name "Email", R name "subject"')
-        self.commit()
-        rset = req.execute('Any X WHERE X has_text "rick.roll"')
-        self.assertIn(target.eid, [item[0] for item in rset])
+        with self.admin_access.repo_cnx() as cnx:
+            target = cnx.create_entity(u'Email', messageid=u'1234',
+                                       subject=u'rick.roll@dance.com')
+            cnx.commit()
+            rset = cnx.execute('Any X WHERE X has_text "rick.roll"')
+            self.assertIn(target.eid, [item[0] for item in rset])
+            assert cnx.execute('SET A fulltextindexed FALSE '
+                               'WHERE E is CWEType, E name "Email", A is CWAttribute,'
+                               'A from_entity E, A relation_type R, R name "subject"')
+            cnx.commit()
+            rset = cnx.execute('Any X WHERE X has_text "rick.roll"')
+            self.assertFalse(rset)
+            assert cnx.execute('SET A fulltextindexed TRUE '
+                               'WHERE A from_entity E, A relation_type R, '
+                               'E name "Email", R name "subject"')
+            cnx.commit()
+            rset = cnx.execute('Any X WHERE X has_text "rick.roll"')
+            self.assertIn(target.eid, [item[0] for item in rset])
 
     def test_change_fulltext_container(self):
-        req = self.request()
-        target = req.create_entity(u'EmailAddress', address=u'rick.roll@dance.com')
-        target.cw_set(reverse_use_email=req.user)
-        self.commit()
-        rset = req.execute('Any X WHERE X has_text "rick.roll"')
-        self.assertIn(req.user.eid, [item[0] for item in rset])
-        assert self.execute('SET R fulltext_container NULL '
-                            'WHERE R name "use_email"')
-        self.commit()
-        rset = self.execute('Any X WHERE X has_text "rick.roll"')
-        self.assertIn(target.eid, [item[0] for item in rset])
-        assert self.execute('SET R fulltext_container "subject" '
-                            'WHERE R name "use_email"')
-        self.commit()
-        rset = req.execute('Any X WHERE X has_text "rick.roll"')
-        self.assertIn(req.user.eid, [item[0] for item in rset])
+        with self.admin_access.repo_cnx() as cnx:
+            target = cnx.create_entity(u'EmailAddress', address=u'rick.roll@dance.com')
+            target.cw_set(reverse_use_email=cnx.user)
+            cnx.commit()
+            rset = cnx.execute('Any X WHERE X has_text "rick.roll"')
+            self.assertIn(cnx.user.eid, [item[0] for item in rset])
+            assert cnx.execute('SET R fulltext_container NULL '
+                                'WHERE R name "use_email"')
+            cnx.commit()
+            rset = cnx.execute('Any X WHERE X has_text "rick.roll"')
+            self.assertIn(target.eid, [item[0] for item in rset])
+            assert cnx.execute('SET R fulltext_container "subject" '
+                                'WHERE R name "use_email"')
+            cnx.commit()
+            rset = cnx.execute('Any X WHERE X has_text "rick.roll"')
+            self.assertIn(cnx.user.eid, [item[0] for item in rset])
 
     def test_update_constraint(self):
-        rdef = self.schema['Transition'].rdef('type')
-        cstr = rdef.constraint_by_type('StaticVocabularyConstraint')
-        if not getattr(cstr, 'eid', None):
-            self.skipTest('start me alone') # bug in schema reloading, constraint's eid not restored
-        self.execute('SET X value %(v)s WHERE X eid %(x)s',
-                     {'x': cstr.eid, 'v': u"u'normal', u'auto', u'new'"})
-        self.execute('INSERT CWConstraint X: X value %(value)s, X cstrtype CT, EDEF constrained_by X '
-                     'WHERE CT name %(ct)s, EDEF eid %(x)s',
-                     {'ct': 'SizeConstraint', 'value': u'max=10', 'x': rdef.eid})
-        self.commit()
-        cstr = rdef.constraint_by_type('StaticVocabularyConstraint')
-        self.assertEqual(cstr.values, (u'normal', u'auto', u'new'))
-        self.execute('INSERT Transition T: T name "hop", T type "new"')
+        with self.admin_access.repo_cnx() as cnx:
+            rdef = self.schema['Transition'].rdef('type')
+            cstr = rdef.constraint_by_type('StaticVocabularyConstraint')
+            if not getattr(cstr, 'eid', None):
+                # bug in schema reloading, constraint's eid not restored
+                self.skipTest('start me alone')
+            cnx.execute('SET X value %(v)s WHERE X eid %(x)s',
+                         {'x': cstr.eid, 'v': u"u'normal', u'auto', u'new'"})
+            cnx.execute('INSERT CWConstraint X: X value %(value)s, X cstrtype CT, '
+                        'EDEF constrained_by X WHERE CT name %(ct)s, EDEF eid %(x)s',
+                         {'ct': 'SizeConstraint', 'value': u'max=10', 'x': rdef.eid})
+            cnx.commit()
+            cstr = rdef.constraint_by_type('StaticVocabularyConstraint')
+            self.assertEqual(cstr.values, (u'normal', u'auto', u'new'))
+            cnx.execute('INSERT Transition T: T name "hop", T type "new"')
 
 if __name__ == '__main__':
     unittest_main()
--- a/hooks/test/unittest_syncsession.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/hooks/test/unittest_syncsession.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -28,32 +28,46 @@
 class CWPropertyHooksTC(CubicWebTC):
 
     def test_unexistant_cwproperty(self):
-        with self.assertRaises(ValidationError) as cm:
-            self.execute('INSERT CWProperty X: X pkey "bla.bla", X value "hop", X for_user U')
-        cm.exception.translate(unicode)
-        self.assertEqual(cm.exception.errors, {'pkey-subject': 'unknown property key bla.bla'})
-        with self.assertRaises(ValidationError) as cm:
-            self.execute('INSERT CWProperty X: X pkey "bla.bla", X value "hop"')
-        cm.exception.translate(unicode)
-        self.assertEqual(cm.exception.errors, {'pkey-subject': 'unknown property key bla.bla'})
+        with self.admin_access.web_request() as req:
+            with self.assertRaises(ValidationError) as cm:
+                req.execute('INSERT CWProperty X: X pkey "bla.bla", '
+                            'X value "hop", X for_user U')
+            cm.exception.translate(unicode)
+            self.assertEqual(cm.exception.errors,
+                             {'pkey-subject': 'unknown property key bla.bla'})
+
+            with self.assertRaises(ValidationError) as cm:
+                req.execute('INSERT CWProperty X: X pkey "bla.bla", X value "hop"')
+            cm.exception.translate(unicode)
+            self.assertEqual(cm.exception.errors,
+                             {'pkey-subject': 'unknown property key bla.bla'})
 
     def test_site_wide_cwproperty(self):
-        with self.assertRaises(ValidationError) as cm:
-            self.execute('INSERT CWProperty X: X pkey "ui.site-title", X value "hop", X for_user U')
-        self.assertEqual(cm.exception.errors, {'for_user-subject': "site-wide property can't be set for user"})
+        with self.admin_access.web_request() as req:
+            with self.assertRaises(ValidationError) as cm:
+                req.execute('INSERT CWProperty X: X pkey "ui.site-title", '
+                            'X value "hop", X for_user U')
+            self.assertEqual(cm.exception.errors,
+                             {'for_user-subject': "site-wide property can't be set for user"})
 
     def test_system_cwproperty(self):
-        with self.assertRaises(ValidationError) as cm:
-            self.execute('INSERT CWProperty X: X pkey "system.version.cubicweb", X value "hop", X for_user U')
-        self.assertEqual(cm.exception.errors, {'for_user-subject': "site-wide property can't be set for user"})
+        with self.admin_access.web_request() as req:
+            with self.assertRaises(ValidationError) as cm:
+                req.execute('INSERT CWProperty X: X pkey "system.version.cubicweb", '
+                            'X value "hop", X for_user U')
+            self.assertEqual(cm.exception.errors,
+                             {'for_user-subject': "site-wide property can't be set for user"})
 
     def test_bad_type_cwproperty(self):
-        with self.assertRaises(ValidationError) as cm:
-            self.execute('INSERT CWProperty X: X pkey "ui.language", X value "hop", X for_user U')
-        self.assertEqual(cm.exception.errors, {'value-subject': u'unauthorized value'})
-        with self.assertRaises(ValidationError) as cm:
-            self.execute('INSERT CWProperty X: X pkey "ui.language", X value "hop"')
-        self.assertEqual(cm.exception.errors, {'value-subject': u'unauthorized value'})
+        with self.admin_access.web_request() as req:
+            with self.assertRaises(ValidationError) as cm:
+                req.execute('INSERT CWProperty X: X pkey "ui.language", '
+                            'X value "hop", X for_user U')
+            self.assertEqual(cm.exception.errors,
+                             {'value-subject': u'unauthorized value'})
+            with self.assertRaises(ValidationError) as cm:
+                req.execute('INSERT CWProperty X: X pkey "ui.language", X value "hop"')
+            self.assertEqual(cm.exception.errors, {'value-subject': u'unauthorized value'})
 
 if __name__ == '__main__':
     from logilab.common.testlib import unittest_main
--- a/hooks/zmq.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/hooks/zmq.py	Fri Jul 18 17:35:25 2014 +0200
@@ -71,6 +71,7 @@
         address = config.get('zmq-repository-address')
         if not address:
             return
+        self.repo.warning('remote access to the repository via zmq/pickle is deprecated')
         from cubicweb.server import cwzmq
         self.repo.zmq_repo_server = server = cwzmq.ZMQRepositoryServer(self.repo)
         server.connect(address)
--- a/migration.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/migration.py	Fri Jul 18 17:35:25 2014 +0200
@@ -414,7 +414,9 @@
             toremove = (cube,)
         origcubes = self.config._cubes
         basecubes = [c for c in origcubes if not c in toremove]
-        self.config._cubes = tuple(self.config.expand_cubes(basecubes))
+        # don't fake-add any new ones, or we won't be able to really-add them later
+        self.config._cubes = tuple(cube for cube in self.config.expand_cubes(basecubes)
+                                   if cube in origcubes)
         removed = [p for p in origcubes if not p in self.config._cubes]
         if not cube in removed and cube in origcubes:
             raise ConfigurationError("can't remove cube %s, "
--- a/rset.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/rset.py	Fri Jul 18 17:35:25 2014 +0200
@@ -541,7 +541,8 @@
                 else:
                     attr_cols[attr] = i
             else:
-                rdef = eschema.rdef(attr, role)
+                # XXX takefirst=True to remove warning triggered by ambiguous relations
+                rdef = eschema.rdef(attr, role, takefirst=True)
                 # only keep value if it can't be multivalued
                 if rdef.role_cardinality(role) in '1?':
                     rel_cols[(attr, role)] = i
--- a/server/repository.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/server/repository.py	Fri Jul 18 17:35:25 2014 +0200
@@ -880,7 +880,7 @@
         """
         mintime = time() - self.cleanup_session_time
         self.debug('cleaning session unused since %s',
-                   strftime('%T', localtime(mintime)))
+                   strftime('%H:%M:%S', localtime(mintime)))
         nbclosed = 0
         for session in self._sessions.values():
             if session.timestamp < mintime:
--- a/server/serverctl.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/server/serverctl.py	Fri Jul 18 17:35:25 2014 +0200
@@ -677,6 +677,7 @@
     def run(self, args):
         from logilab.common.daemon import daemonize, setugid
         from cubicweb.cwctl import init_cmdline_log_threshold
+        print 'WARNING: Standalone repository with pyro or zmq access is deprecated'
         appid = args[0]
         debug = self['debug']
         if sys.platform == 'win32' and not debug:
--- a/server/sources/datafeed.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/server/sources/datafeed.py	Fri Jul 18 17:35:25 2014 +0200
@@ -126,18 +126,18 @@
         self.parser_id = source_entity.parser
         self.load_mapping(source_entity._cw)
 
-    def _get_parser(self, session, **kwargs):
+    def _get_parser(self, cnx, **kwargs):
         return self.repo.vreg['parsers'].select(
-            self.parser_id, session, source=self, **kwargs)
+            self.parser_id, cnx, source=self, **kwargs)
 
-    def load_mapping(self, session):
+    def load_mapping(self, cnx):
         self.mapping = {}
         self.mapping_idx = {}
         try:
-            parser = self._get_parser(session)
+            parser = self._get_parser(cnx)
         except (RegistryNotFound, ObjectNotFound):
             return # no parser yet, don't go further
-        self._load_mapping(session, parser=parser)
+        self._load_mapping(cnx, parser=parser)
 
     def add_schema_config(self, schemacfg, checkonly=False, parser=None):
         """added CWSourceSchemaConfig, modify mapping accordingly"""
@@ -159,7 +159,7 @@
     def update_latest_retrieval(self, cnx):
         self.latest_retrieval = datetime.utcnow()
         cnx.execute('SET X latest_retrieval %(date)s WHERE X eid %(x)s',
-                        {'x': self.eid, 'date': self.latest_retrieval})
+                    {'x': self.eid, 'date': self.latest_retrieval})
         cnx.commit()
 
     def acquire_synchronization_lock(self, cnx):
@@ -178,7 +178,7 @@
 
     def release_synchronization_lock(self, cnx):
         cnx.execute('SET X in_synchronization NULL WHERE X eid %(x)s',
-                        {'x': self.eid})
+                    {'x': self.eid})
         cnx.commit()
 
     def pull_data(self, cnx, force=False, raise_on_error=False):
@@ -238,7 +238,7 @@
                 error = True
         return error
 
-    def before_entity_insertion(self, session, lid, etype, eid, sourceparams):
+    def before_entity_insertion(self, cnx, lid, etype, eid, sourceparams):
         """called by the repository when an eid has been attributed for an
         entity stored here but the entity has not been inserted in the system
         table yet.
@@ -247,40 +247,40 @@
         entity.
         """
         entity = super(DataFeedSource, self).before_entity_insertion(
-            session, lid, etype, eid, sourceparams)
+            cnx, lid, etype, eid, sourceparams)
         entity.cw_edited['cwuri'] = lid.decode('utf-8')
         entity.cw_edited.set_defaults()
         sourceparams['parser'].before_entity_copy(entity, sourceparams)
         return entity
 
-    def after_entity_insertion(self, session, lid, entity, sourceparams):
+    def after_entity_insertion(self, cnx, lid, entity, sourceparams):
         """called by the repository after an entity stored here has been
         inserted in the system table.
         """
-        relations = preprocess_inlined_relations(session, entity)
-        if session.is_hook_category_activated('integrity'):
+        relations = preprocess_inlined_relations(cnx, entity)
+        if cnx.is_hook_category_activated('integrity'):
             entity.cw_edited.check(creation=True)
-        self.repo.system_source.add_entity(session, entity)
+        self.repo.system_source.add_entity(cnx, entity)
         entity.cw_edited.saved = entity._cw_is_saved = True
         sourceparams['parser'].after_entity_copy(entity, sourceparams)
         # call hooks for inlined relations
         call_hooks = self.repo.hm.call_hooks
         if self.should_call_hooks:
             for attr, value in relations:
-                call_hooks('before_add_relation', session,
+                call_hooks('before_add_relation', cnx,
                            eidfrom=entity.eid, rtype=attr, eidto=value)
-                call_hooks('after_add_relation', session,
+                call_hooks('after_add_relation', cnx,
                            eidfrom=entity.eid, rtype=attr, eidto=value)
 
-    def source_cwuris(self, session):
+    def source_cwuris(self, cnx):
         sql = ('SELECT extid, eid, type FROM entities, cw_source_relation '
                'WHERE entities.eid=cw_source_relation.eid_from '
                'AND cw_source_relation.eid_to=%s' % self.eid)
         return dict((b64decode(uri), (eid, type))
-                    for uri, eid, type in session.system_sql(sql).fetchall())
+                    for uri, eid, type in cnx.system_sql(sql).fetchall())
 
-    def init_import_log(self, session, **kwargs):
-        dataimport = session.create_entity('CWDataImport', cw_import_of=self,
+    def init_import_log(self, cnx, **kwargs):
+        dataimport = cnx.create_entity('CWDataImport', cw_import_of=self,
                                            start_timestamp=datetime.utcnow(),
                                            **kwargs)
         dataimport.init()
@@ -290,8 +290,8 @@
 class DataFeedParser(AppObject):
     __registry__ = 'parsers'
 
-    def __init__(self, session, source, sourceuris=None, import_log=None, **kwargs):
-        super(DataFeedParser, self).__init__(session, **kwargs)
+    def __init__(self, cnx, source, sourceuris=None, import_log=None, **kwargs):
+        super(DataFeedParser, self).__init__(cnx, **kwargs)
         self.source = source
         self.sourceuris = sourceuris
         self.import_log = import_log
@@ -345,20 +345,20 @@
         """return an entity for the given uri. May return None if it should be
         skipped
         """
-        session = self._cw
+        cnx = self._cw
         # if cwsource is specified and repository has a source with the same
         # name, call extid2eid on that source so entity will be properly seen as
         # coming from this source
         source_uri = sourceparams.pop('cwsource', None)
         if source_uri is not None and source_uri != 'system':
-            source = session.repo.sources_by_uri.get(source_uri, self.source)
+            source = cnx.repo.sources_by_uri.get(source_uri, self.source)
         else:
             source = self.source
         sourceparams['parser'] = self
         if isinstance(uri, unicode):
             uri = uri.encode('utf-8')
         try:
-            eid = session.repo.extid2eid(source, str(uri), etype, session,
+            eid = cnx.repo.extid2eid(source, str(uri), etype, cnx,
                                          sourceparams=sourceparams)
         except ValidationError as ex:
             # XXX use critical so they are seen during tests. Should consider
@@ -373,14 +373,14 @@
             # Don't give etype to entity_from_eid so we get UnknownEid if the
             # entity has been removed
             try:
-                entity = session.entity_from_eid(-eid)
+                entity = cnx.entity_from_eid(-eid)
             except UnknownEid:
                 return None
             self.notify_updated(entity) # avoid later update from the source's data
             return entity
         if self.sourceuris is not None:
             self.sourceuris.pop(str(uri), None)
-        return session.entity_from_eid(eid, etype)
+        return cnx.entity_from_eid(eid, etype)
 
     def process(self, url, raise_on_error=False):
         """main callback: process the url"""
@@ -411,7 +411,7 @@
         """
         return True
 
-    def handle_deletion(self, config, session, myuris):
+    def handle_deletion(self, config, cnx, myuris):
         if config['delete-entities'] and myuris:
             byetype = {}
             for extid, (eid, etype) in myuris.iteritems():
@@ -419,10 +419,9 @@
                     byetype.setdefault(etype, []).append(str(eid))
             for etype, eids in byetype.iteritems():
                 self.warning('delete %s %s entities', len(eids), etype)
-                session.set_cnxset()
-                session.execute('DELETE %s X WHERE X eid IN (%s)'
-                                % (etype, ','.join(eids)))
-                session.commit()
+                cnx.execute('DELETE %s X WHERE X eid IN (%s)'
+                            % (etype, ','.join(eids)))
+                cnx.commit()
 
     def update_if_necessary(self, entity, attrs):
         entity.complete(tuple(attrs))
@@ -450,13 +449,8 @@
             self.import_log.record_error(str(ex))
             return True
         error = False
-        # Check whether self._cw is a session or a connection
-        if getattr(self._cw, 'commit', None) is not None:
-            commit = self._cw.commit
-            rollback = self._cw.rollback
-        else:
-            commit = self._cw.cnx.commit
-            rollback = self._cw.cnx.rollback
+        commit = self._cw.commit
+        rollback = self._cw.rollback
         for args in parsed:
             try:
                 self.process_item(*args)
--- a/server/test/data/schema.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/server/test/data/schema.py	Fri Jul 18 17:35:25 2014 +0200
@@ -202,7 +202,6 @@
     name = 'ecrit_par'
     subject = 'Note'
     object ='Personne'
-    constraints = [RQLConstraint('E concerns P, S version_of P')]
     cardinality = '?*'
 
 class ecrit_par_2(RelationDefinition):
--- a/server/test/unittest_datafeed.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/server/test/unittest_datafeed.py	Fri Jul 18 17:35:25 2014 +0200
@@ -104,11 +104,11 @@
                 self.assertEqual(self.repo._extid_cache['http://www.cubicweb.org/'],
                                  entity.eid)
 
-        self.assertEqual(dfsource.source_cwuris(self.session),
-                         {'http://www.cubicweb.org/': (entity.eid, 'Card')}
-                         )
-        self.assertTrue(dfsource.latest_retrieval)
-        self.assertTrue(dfsource.fresh())
+                self.assertEqual(dfsource.source_cwuris(cnx),
+                                 {'http://www.cubicweb.org/': (entity.eid, 'Card')}
+                             )
+                self.assertTrue(dfsource.latest_retrieval)
+                self.assertTrue(dfsource.fresh())
 
         # test_rename_source
         with self.admin_access.repo_cnx() as cnx:
--- a/server/test/unittest_querier.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/server/test/unittest_querier.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,5 +1,5 @@
 # -*- coding: iso-8859-1 -*-
-# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -110,167 +110,193 @@
         pass
 
     def test_preprocess_1(self):
-        reid = self.execute('Any X WHERE X is CWRType, X name "owned_by"')[0][0]
-        rqlst = self._prepare('Any COUNT(RDEF) WHERE RDEF relation_type X, X eid %(x)s', {'x': reid})
-        self.assertEqual(rqlst.solutions, [{'RDEF': 'CWAttribute'}, {'RDEF': 'CWRelation'}])
+        with self.session.new_cnx() as cnx:
+            reid = cnx.execute('Any X WHERE X is CWRType, X name "owned_by"')[0][0]
+            rqlst = self._prepare(cnx, 'Any COUNT(RDEF) WHERE RDEF relation_type X, X eid %(x)s',
+                                  {'x': reid})
+            self.assertEqual([{'RDEF': 'CWAttribute'}, {'RDEF': 'CWRelation'}],
+                             rqlst.solutions)
 
     def test_preprocess_2(self):
-        teid = self.execute("INSERT Tag X: X name 'tag'")[0][0]
-        #geid = self.execute("CWGroup G WHERE G name 'users'")[0][0]
-        #self.execute("SET X tags Y WHERE X eid %(t)s, Y eid %(g)s",
-        #             {'g': geid, 't': teid}, 'g')
-        rqlst = self._prepare('Any X WHERE E eid %(x)s, E tags X', {'x': teid})
-        # the query may be optimized, should keep only one solution
-        # (any one, etype will be discarded)
-        self.assertEqual(len(rqlst.solutions), 1)
+        with self.session.new_cnx() as cnx:
+            teid = cnx.execute("INSERT Tag X: X name 'tag'")[0][0]
+            #geid = self.execute("CWGroup G WHERE G name 'users'")[0][0]
+            #self.execute("SET X tags Y WHERE X eid %(t)s, Y eid %(g)s",
+            #             {'g': geid, 't': teid}, 'g')
+            rqlst = self._prepare(cnx, 'Any X WHERE E eid %(x)s, E tags X', {'x': teid})
+            # the query may be optimized, should keep only one solution
+            # (any one, etype will be discarded)
+            self.assertEqual(1, len(rqlst.solutions))
+
+    def assertRQLEqual(self, expected, got):
+        from rql import parse
+        self.assertMultiLineEqual(unicode(parse(expected)),
+                                  unicode(parse(got)))
 
     def test_preprocess_security(self):
-        plan = self._prepare_plan('Any ETN,COUNT(X) GROUPBY ETN '
-                                  'WHERE X is ET, ET name ETN')
-        plan.cnx = self.user_groups_session('users')
-        union = plan.rqlst
-        plan.preprocess(union)
-        self.assertEqual(len(union.children), 1)
-        self.assertEqual(len(union.children[0].with_), 1)
-        subq = union.children[0].with_[0].query
-        self.assertEqual(len(subq.children), 4)
-        self.assertEqual([t.as_string() for t in union.children[0].selection],
-                          ['ETN','COUNT(X)'])
-        self.assertEqual([t.as_string() for t in union.children[0].groupby],
-                          ['ETN'])
-        partrqls = sorted(((rqlst.as_string(), rqlst.solutions) for rqlst in subq.children))
-        rql, solutions = partrqls[0]
-        self.assertEqual(rql,
-                          'Any ETN,X WHERE X is ET, ET name ETN, (EXISTS(X owned_by %(B)s))'
-                          ' OR ((((EXISTS(D concerne C?, C owned_by %(B)s, X identity D, C is Division, D is Affaire))'
-                          ' OR (EXISTS(H concerne G?, G owned_by %(B)s, G is SubDivision, X identity H, H is Affaire)))'
-                          ' OR (EXISTS(I concerne F?, F owned_by %(B)s, F is Societe, X identity I, I is Affaire)))'
-                          ' OR (EXISTS(J concerne E?, E owned_by %(B)s, E is Note, X identity J, J is Affaire)))'
-                          ', ET is CWEType, X is Affaire')
-        self.assertEqual(solutions, [{'C': 'Division',
-                                       'D': 'Affaire',
-                                       'E': 'Note',
-                                       'F': 'Societe',
-                                       'G': 'SubDivision',
-                                       'H': 'Affaire',
-                                       'I': 'Affaire',
-                                       'J': 'Affaire',
-                                       'X': 'Affaire',
-                                       'ET': 'CWEType', 'ETN': 'String'}])
-        rql, solutions = partrqls[1]
-        self.assertEqual(rql,  'Any ETN,X WHERE X is ET, ET name ETN, ET is CWEType, X is IN(BaseTransition, Bookmark, CWAttribute, CWCache, CWConstraint, CWConstraintType, CWEType, CWGroup, CWPermission, CWProperty, CWRType, CWRelation, CWSource, CWUniqueTogetherConstraint, CWUser, Card, Comment, Division, Email, EmailPart, EmailThread, ExternalUri, File, Folder, Note, Old, Personne, RQLExpression, Societe, State, SubDivision, SubWorkflowExitPoint, Tag, TrInfo, Transition, Workflow, WorkflowTransition)')
-        self.assertListEqual(sorted(solutions),
-                              sorted([{'X': 'BaseTransition', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'Bookmark', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'Card', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'Comment', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'Division', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'CWCache', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'CWConstraint', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'CWConstraintType', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'CWEType', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'CWAttribute', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'CWGroup', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'CWRelation', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'CWPermission', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'CWProperty', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'CWRType', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'CWSource', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'CWUniqueTogetherConstraint', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'CWUser', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'Email', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'EmailPart', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'EmailThread', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'ExternalUri', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'File', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'Folder', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'Note', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'Old', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'Personne', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'RQLExpression', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'Societe', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'State', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'SubDivision', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'SubWorkflowExitPoint', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'Tag', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'Transition', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'TrInfo', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'Workflow', 'ETN': 'String', 'ET': 'CWEType'},
-                                      {'X': 'WorkflowTransition', 'ETN': 'String', 'ET': 'CWEType'}]))
-        rql, solutions = partrqls[2]
-        self.assertEqual(rql,
-                         'Any ETN,X WHERE X is ET, ET name ETN, EXISTS(%(D)s use_email X), '
-                         'ET is CWEType, X is EmailAddress')
-        self.assertEqual(solutions, [{'X': 'EmailAddress', 'ET': 'CWEType', 'ETN': 'String'}])
-        rql, solutions = partrqls[3]
-        self.assertEqual(rql,
-                          'Any ETN,X WHERE X is ET, ET name ETN, EXISTS(X owned_by %(C)s), '
-                          'ET is CWEType, X is Basket')
-        self.assertEqual(solutions, [{'X': 'Basket', 'ET': 'CWEType', 'ETN': 'String'}])
+        s = self.user_groups_session('users')
+        with s.new_cnx() as cnx:
+            plan = self._prepare_plan(cnx, 'Any ETN,COUNT(X) GROUPBY ETN '
+                                      'WHERE X is ET, ET name ETN')
+            union = plan.rqlst
+            plan.preprocess(union)
+            self.assertEqual(len(union.children), 1)
+            self.assertEqual(len(union.children[0].with_), 1)
+            subq = union.children[0].with_[0].query
+            self.assertEqual(len(subq.children), 4)
+            self.assertEqual([t.as_string() for t in union.children[0].selection],
+                              ['ETN','COUNT(X)'])
+            self.assertEqual([t.as_string() for t in union.children[0].groupby],
+                              ['ETN'])
+            partrqls = sorted(((rqlst.as_string(), rqlst.solutions) for rqlst in subq.children))
+            rql, solutions = partrqls[0]
+            self.assertRQLEqual(rql,
+                                'Any ETN,X WHERE X is ET, ET name ETN, (EXISTS(X owned_by %(B)s))'
+                                ' OR ((((EXISTS(D concerne C?, C owned_by %(B)s, '
+                                '               X identity D, C is Division, D is Affaire))'
+                                ' OR (EXISTS(H concerne G?, G owned_by %(B)s, G is SubDivision, '
+                                '            X identity H, H is Affaire)))'
+                                ' OR (EXISTS(I concerne F?, F owned_by %(B)s, F is Societe, '
+                                '            X identity I, I is Affaire)))'
+                                ' OR (EXISTS(J concerne E?, E owned_by %(B)s, E is Note, '
+                                '            X identity J, J is Affaire)))'
+                                ', ET is CWEType, X is Affaire')
+            self.assertEqual(solutions, [{'C': 'Division',
+                                           'D': 'Affaire',
+                                           'E': 'Note',
+                                           'F': 'Societe',
+                                           'G': 'SubDivision',
+                                           'H': 'Affaire',
+                                           'I': 'Affaire',
+                                           'J': 'Affaire',
+                                           'X': 'Affaire',
+                                           'ET': 'CWEType', 'ETN': 'String'}])
+            rql, solutions = partrqls[1]
+            self.assertRQLEqual(rql,  'Any ETN,X WHERE X is ET, ET name ETN, ET is CWEType, '
+                                'X is IN(BaseTransition, Bookmark, CWAttribute, CWCache, CWConstraint, '
+                                '        CWConstraintType, CWEType, CWGroup, CWPermission, CWProperty, CWRType, '
+                                '        CWRelation, CWSource, CWUniqueTogetherConstraint, CWUser, Card, Comment, '
+                                '        Division, Email, EmailPart, EmailThread, ExternalUri, File, Folder, Note, '
+                                '        Old, Personne, RQLExpression, Societe, State, SubDivision, '
+                                '        SubWorkflowExitPoint, Tag, TrInfo, Transition, Workflow, WorkflowTransition)')
+            self.assertListEqual(sorted(solutions),
+                                  sorted([{'X': 'BaseTransition', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'Bookmark', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'Card', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'Comment', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'Division', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'CWCache', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'CWConstraint', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'CWConstraintType', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'CWEType', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'CWAttribute', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'CWGroup', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'CWRelation', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'CWPermission', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'CWProperty', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'CWRType', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'CWSource', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'CWUniqueTogetherConstraint', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'CWUser', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'Email', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'EmailPart', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'EmailThread', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'ExternalUri', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'File', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'Folder', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'Note', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'Old', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'Personne', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'RQLExpression', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'Societe', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'State', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'SubDivision', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'SubWorkflowExitPoint', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'Tag', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'Transition', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'TrInfo', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'Workflow', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'WorkflowTransition', 'ETN': 'String', 'ET': 'CWEType'}]))
+            rql, solutions = partrqls[2]
+            self.assertEqual(rql,
+                             'Any ETN,X WHERE X is ET, ET name ETN, EXISTS(%(D)s use_email X), '
+                             'ET is CWEType, X is EmailAddress')
+            self.assertEqual(solutions, [{'X': 'EmailAddress', 'ET': 'CWEType', 'ETN': 'String'}])
+            rql, solutions = partrqls[3]
+            self.assertEqual(rql,
+                              'Any ETN,X WHERE X is ET, ET name ETN, EXISTS(X owned_by %(C)s), '
+                              'ET is CWEType, X is Basket')
+            self.assertEqual(solutions, [{'X': 'Basket', 'ET': 'CWEType', 'ETN': 'String'}])
 
     def test_preprocess_security_aggregat(self):
-        plan = self._prepare_plan('Any MAX(X)')
-        plan.cnx = self.user_groups_session('users')
-        union = plan.rqlst
-        plan.preprocess(union)
-        self.assertEqual(len(union.children), 1)
-        self.assertEqual(len(union.children[0].with_), 1)
-        subq = union.children[0].with_[0].query
-        self.assertEqual(len(subq.children), 4)
-        self.assertEqual([t.as_string() for t in union.children[0].selection],
-                          ['MAX(X)'])
+        s = self.user_groups_session('users')
+        with s.new_cnx() as cnx:
+            plan = self._prepare_plan(cnx, 'Any MAX(X)')
+            union = plan.rqlst
+            plan.preprocess(union)
+            self.assertEqual(len(union.children), 1)
+            self.assertEqual(len(union.children[0].with_), 1)
+            subq = union.children[0].with_[0].query
+            self.assertEqual(len(subq.children), 4)
+            self.assertEqual([t.as_string() for t in union.children[0].selection],
+                              ['MAX(X)'])
 
     def test_preprocess_nonregr(self):
-        rqlst = self._prepare('Any S ORDERBY SI WHERE NOT S ecrit_par O, S para SI')
-        self.assertEqual(len(rqlst.solutions), 1)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any S ORDERBY SI WHERE NOT S ecrit_par O, S para SI')
+            self.assertEqual(len(rqlst.solutions), 1)
 
     def test_build_description(self):
         # should return an empty result set
-        rset = self.execute('Any X WHERE X eid %(x)s', {'x': self.session.user.eid})
+        rset = self.qexecute('Any X WHERE X eid %(x)s', {'x': self.session.user.eid})
         self.assertEqual(rset.description[0][0], 'CWUser')
-        rset = self.execute('Any 1')
+        rset = self.qexecute('Any 1')
         self.assertEqual(rset.description[0][0], 'Int')
-        rset = self.execute('Any TRUE')
+        rset = self.qexecute('Any TRUE')
         self.assertEqual(rset.description[0][0], 'Boolean')
-        rset = self.execute('Any "hop"')
+        rset = self.qexecute('Any "hop"')
         self.assertEqual(rset.description[0][0], 'String')
-        rset = self.execute('Any TODAY')
+        rset = self.qexecute('Any TODAY')
         self.assertEqual(rset.description[0][0], 'Date')
-        rset = self.execute('Any NOW')
+        rset = self.qexecute('Any NOW')
         self.assertEqual(rset.description[0][0], 'Datetime')
-        rset = self.execute('Any %(x)s', {'x': 1})
+        rset = self.qexecute('Any %(x)s', {'x': 1})
         self.assertEqual(rset.description[0][0], 'Int')
-        rset = self.execute('Any %(x)s', {'x': 1L})
+        rset = self.qexecute('Any %(x)s', {'x': 1L})
         self.assertEqual(rset.description[0][0], 'Int')
-        rset = self.execute('Any %(x)s', {'x': True})
+        rset = self.qexecute('Any %(x)s', {'x': True})
         self.assertEqual(rset.description[0][0], 'Boolean')
-        rset = self.execute('Any %(x)s', {'x': 1.0})
+        rset = self.qexecute('Any %(x)s', {'x': 1.0})
         self.assertEqual(rset.description[0][0], 'Float')
-        rset = self.execute('Any %(x)s', {'x': datetime.now()})
+        rset = self.qexecute('Any %(x)s', {'x': datetime.now()})
         self.assertEqual(rset.description[0][0], 'Datetime')
-        rset = self.execute('Any %(x)s', {'x': 'str'})
+        rset = self.qexecute('Any %(x)s', {'x': 'str'})
         self.assertEqual(rset.description[0][0], 'String')
-        rset = self.execute('Any %(x)s', {'x': u'str'})
+        rset = self.qexecute('Any %(x)s', {'x': u'str'})
         self.assertEqual(rset.description[0][0], 'String')
 
     def test_build_descr1(self):
-        rset = self.execute('(Any U,L WHERE U login L) UNION (Any G,N WHERE G name N, G is CWGroup)')
-        rset.req = self.session
-        orig_length = len(rset)
-        rset.rows[0][0] = 9999999
-        description = manual_build_descr(rset.req, rset.syntax_tree(), None, rset.rows)
-        self.assertEqual(len(description), orig_length - 1)
-        self.assertEqual(len(rset.rows), orig_length - 1)
-        self.assertNotEqual(rset.rows[0][0], 9999999)
+        with self.session.new_cnx() as cnx:
+            rset = cnx.execute('(Any U,L WHERE U login L) UNION '
+                               '(Any G,N WHERE G name N, G is CWGroup)')
+            # rset.req = self.session
+            orig_length = len(rset)
+            rset.rows[0][0] = 9999999
+            description = manual_build_descr(cnx, rset.syntax_tree(), None, rset.rows)
+            self.assertEqual(len(description), orig_length - 1)
+            self.assertEqual(len(rset.rows), orig_length - 1)
+            self.assertNotEqual(rset.rows[0][0], 9999999)
 
     def test_build_descr2(self):
-        rset = self.execute('Any X,Y WITH X,Y BEING ((Any G,NULL WHERE G is CWGroup) UNION (Any U,G WHERE U in_group G))')
+        rset = self.qexecute('Any X,Y WITH X,Y BEING ((Any G,NULL WHERE G is CWGroup) UNION '
+                             '(Any U,G WHERE U in_group G))')
         for x, y in rset.description:
             if y is not None:
                 self.assertEqual(y, 'CWGroup')
 
     def test_build_descr3(self):
-        rset = self.execute('(Any G,NULL WHERE G is CWGroup) UNION (Any U,G WHERE U in_group G)')
+        rset = self.qexecute('(Any G,NULL WHERE G is CWGroup) UNION '
+                             '(Any U,G WHERE U in_group G)')
         for x, y in rset.description:
             if y is not None:
                 self.assertEqual(y, 'CWGroup')
@@ -281,284 +307,298 @@
     tearDownClass = classmethod(tearDownClass)
 
     def test_encoding_pb(self):
-        self.assertRaises(RQLSyntaxError, self.execute,
+        self.assertRaises(RQLSyntaxError, self.qexecute,
                           'Any X WHERE X is CWRType, X name "öwned_by"')
 
     def test_unknown_eid(self):
         # should return an empty result set
-        self.assertFalse(self.execute('Any X WHERE X eid 99999999'))
+        self.assertFalse(self.qexecute('Any X WHERE X eid 99999999'))
 
     def test_typed_eid(self):
         # should return an empty result set
-        rset = self.execute('Any X WHERE X eid %(x)s', {'x': '1'})
+        rset = self.qexecute('Any X WHERE X eid %(x)s', {'x': '1'})
         self.assertIsInstance(rset[0][0], (int, long))
 
     def test_bytes_storage(self):
-        feid = self.execute('INSERT File X: X data_name "foo.pdf", X data_format "text/plain", X data %(data)s',
+        feid = self.qexecute('INSERT File X: X data_name "foo.pdf", '
+                             'X data_format "text/plain", X data %(data)s',
                             {'data': Binary("xxx")})[0][0]
-        fdata = self.execute('Any D WHERE X data D, X eid %(x)s', {'x': feid})[0][0]
+        fdata = self.qexecute('Any D WHERE X data D, X eid %(x)s', {'x': feid})[0][0]
         self.assertIsInstance(fdata, Binary)
         self.assertEqual(fdata.getvalue(), 'xxx')
 
     # selection queries tests #################################################
 
     def test_select_1(self):
-        rset = self.execute('Any X ORDERBY X WHERE X is CWGroup')
+        rset = self.qexecute('Any X ORDERBY X WHERE X is CWGroup')
         result, descr = rset.rows, rset.description
         self.assertEqual(tuplify(result), [(2,), (3,), (4,), (5,)])
         self.assertEqual(descr, [('CWGroup',), ('CWGroup',), ('CWGroup',), ('CWGroup',)])
 
     def test_select_2(self):
-        rset = self.execute('Any X ORDERBY N WHERE X is CWGroup, X name N')
+        rset = self.qexecute('Any X ORDERBY N WHERE X is CWGroup, X name N')
         self.assertEqual(tuplify(rset.rows), [(2,), (3,), (4,), (5,)])
         self.assertEqual(rset.description, [('CWGroup',), ('CWGroup',), ('CWGroup',), ('CWGroup',)])
-        rset = self.execute('Any X ORDERBY N DESC WHERE X is CWGroup, X name N')
+        rset = self.qexecute('Any X ORDERBY N DESC WHERE X is CWGroup, X name N')
         self.assertEqual(tuplify(rset.rows), [(5,), (4,), (3,), (2,)])
 
     def test_select_3(self):
-        rset = self.execute('Any N GROUPBY N WHERE X is CWGroup, X name N')
+        rset = self.qexecute('Any N GROUPBY N WHERE X is CWGroup, X name N')
         result, descr = rset.rows, rset.description
         result.sort()
         self.assertEqual(tuplify(result), [('guests',), ('managers',), ('owners',), ('users',)])
         self.assertEqual(descr, [('String',), ('String',), ('String',), ('String',)])
 
     def test_select_is(self):
-        rset = self.execute('Any X, TN ORDERBY TN LIMIT 10 WHERE X is T, T name TN')
+        rset = self.qexecute('Any X, TN ORDERBY TN LIMIT 10 WHERE X is T, T name TN')
         result, descr = rset.rows, rset.description
         self.assertEqual(result[0][1], descr[0][0])
 
     def test_select_is_aggr(self):
-        rset = self.execute('Any TN, COUNT(X) GROUPBY TN ORDERBY 2 DESC WHERE X is T, T name TN')
+        rset = self.qexecute('Any TN, COUNT(X) GROUPBY TN ORDERBY 2 DESC WHERE X is T, T name TN')
         result, descr = rset.rows, rset.description
         self.assertEqual(descr[0][0], 'String')
         self.assertEqual(descr[0][1], 'Int')
         self.assertEqual(result[0][0], 'CWRelation') # XXX may change as schema evolve
 
     def test_select_groupby_orderby(self):
-        rset = self.execute('Any N GROUPBY N ORDERBY N WHERE X is CWGroup, X name N')
+        rset = self.qexecute('Any N GROUPBY N ORDERBY N WHERE X is CWGroup, X name N')
         self.assertEqual(tuplify(rset.rows), [('guests',), ('managers',), ('owners',), ('users',)])
         self.assertEqual(rset.description, [('String',), ('String',), ('String',), ('String',)])
 
     def test_select_complex_groupby(self):
-        rset = self.execute('Any N GROUPBY N WHERE X name N')
-        rset = self.execute('Any N,MAX(D) GROUPBY N LIMIT 5 WHERE X name N, X creation_date D')
+        rset = self.qexecute('Any N GROUPBY N WHERE X name N')
+        rset = self.qexecute('Any N,MAX(D) GROUPBY N LIMIT 5 WHERE X name N, X creation_date D')
 
     def test_select_inlined_groupby(self):
-        seid = self.execute('State X WHERE X name "deactivated"')[0][0]
-        rset = self.execute('Any U,L,S GROUPBY U,L,S WHERE X in_state S, U login L, S eid %s' % seid)
+        seid = self.qexecute('State X WHERE X name "deactivated"')[0][0]
+        rset = self.qexecute('Any U,L,S GROUPBY U,L,S WHERE X in_state S, U login L, S eid %s' % seid)
 
     def test_select_groupby_funccall(self):
-        rset = self.execute('Any YEAR(CD), COUNT(X) GROUPBY YEAR(CD) WHERE X is CWUser, X creation_date CD')
+        rset = self.qexecute('Any YEAR(CD), COUNT(X) GROUPBY YEAR(CD) '
+                             'WHERE X is CWUser, X creation_date CD')
         self.assertListEqual(rset.rows, [[date.today().year, 2]])
 
     def test_select_groupby_colnumber(self):
-        rset = self.execute('Any YEAR(CD), COUNT(X) GROUPBY 1 WHERE X is CWUser, X creation_date CD')
+        rset = self.qexecute('Any YEAR(CD), COUNT(X) GROUPBY 1 '
+                             'WHERE X is CWUser, X creation_date CD')
         self.assertListEqual(rset.rows, [[date.today().year, 2]])
 
     def test_select_complex_orderby(self):
-        rset1 = self.execute('Any N ORDERBY N WHERE X name N')
+        rset1 = self.qexecute('Any N ORDERBY N WHERE X name N')
         self.assertEqual(sorted(rset1.rows), rset1.rows)
-        rset = self.execute('Any N ORDERBY N LIMIT 5 OFFSET 1 WHERE X name N')
+        rset = self.qexecute('Any N ORDERBY N LIMIT 5 OFFSET 1 WHERE X name N')
         self.assertEqual(rset.rows[0][0], rset1.rows[1][0])
         self.assertEqual(len(rset), 5)
 
     def test_select_5(self):
-        rset = self.execute('Any X, TMP ORDERBY TMP WHERE X name TMP, X is CWGroup')
-        self.assertEqual(tuplify(rset.rows), [(2, 'guests',), (3, 'managers',), (4, 'owners',), (5, 'users',)])
-        self.assertEqual(rset.description, [('CWGroup', 'String',), ('CWGroup', 'String',), ('CWGroup', 'String',), ('CWGroup', 'String',)])
+        rset = self.qexecute('Any X, TMP ORDERBY TMP WHERE X name TMP, X is CWGroup')
+        self.assertEqual(tuplify(rset.rows),
+                         [(2, 'guests',),
+                          (3, 'managers',),
+                          (4, 'owners',),
+                          (5, 'users',)])
+        self.assertEqual(rset.description,
+                         [('CWGroup', 'String',),
+                          ('CWGroup', 'String',),
+                          ('CWGroup', 'String',),
+                          ('CWGroup', 'String',)])
 
     def test_select_6(self):
-        self.execute("INSERT Personne X: X nom 'bidule'")[0]
-        rset = self.execute('Any Y where X name TMP, Y nom in (TMP, "bidule")')
+        self.qexecute("INSERT Personne X: X nom 'bidule'")[0]
+        rset = self.qexecute('Any Y where X name TMP, Y nom in (TMP, "bidule")')
         #self.assertEqual(rset.description, [('Personne',), ('Personne',)])
         self.assertIn(('Personne',), rset.description)
-        rset = self.execute('DISTINCT Any Y where X name TMP, Y nom in (TMP, "bidule")')
+        rset = self.qexecute('DISTINCT Any Y where X name TMP, Y nom in (TMP, "bidule")')
         self.assertIn(('Personne',), rset.description)
 
     def test_select_not_attr(self):
-        peid = self.execute("INSERT Personne X: X nom 'bidule'")[0][0]
-        seid = self.execute("INSERT Societe X: X nom 'chouette'")[0][0]
-        rset = self.execute('Personne X WHERE NOT X nom "bidule"')
+        peid = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0]
+        seid = self.qexecute("INSERT Societe X: X nom 'chouette'")[0][0]
+        rset = self.qexecute('Personne X WHERE NOT X nom "bidule"')
         self.assertEqual(len(rset.rows), 0, rset.rows)
-        rset = self.execute('Personne X WHERE NOT X nom "bid"')
+        rset = self.qexecute('Personne X WHERE NOT X nom "bid"')
         self.assertEqual(len(rset.rows), 1, rset.rows)
-        self.execute("SET P travaille S WHERE P nom 'bidule', S nom 'chouette'")
-        rset = self.execute('Personne X WHERE NOT X travaille S')
+        self.qexecute("SET P travaille S WHERE P nom 'bidule', S nom 'chouette'")
+        rset = self.qexecute('Personne X WHERE NOT X travaille S')
         self.assertEqual(len(rset.rows), 0, rset.rows)
 
     def test_select_is_in(self):
-        self.execute("INSERT Personne X: X nom 'bidule'")
-        self.execute("INSERT Societe X: X nom 'chouette'")
-        self.assertEqual(len(self.execute("Any X WHERE X is IN (Personne, Societe)")),
+        self.qexecute("INSERT Personne X: X nom 'bidule'")
+        self.qexecute("INSERT Societe X: X nom 'chouette'")
+        self.assertEqual(len(self.qexecute("Any X WHERE X is IN (Personne, Societe)")),
                           2)
 
     def test_select_not_rel(self):
-        self.execute("INSERT Personne X: X nom 'bidule'")
-        self.execute("INSERT Societe X: X nom 'chouette'")
-        self.execute("INSERT Personne X: X nom 'autre'")
-        self.execute("SET P travaille S WHERE P nom 'bidule', S nom 'chouette'")
-        rset = self.execute('Personne X WHERE NOT X travaille S')
+        self.qexecute("INSERT Personne X: X nom 'bidule'")
+        self.qexecute("INSERT Societe X: X nom 'chouette'")
+        self.qexecute("INSERT Personne X: X nom 'autre'")
+        self.qexecute("SET P travaille S WHERE P nom 'bidule', S nom 'chouette'")
+        rset = self.qexecute('Personne X WHERE NOT X travaille S')
         self.assertEqual(len(rset.rows), 1, rset.rows)
-        rset = self.execute('Personne X WHERE NOT X travaille S, S nom "chouette"')
+        rset = self.qexecute('Personne X WHERE NOT X travaille S, S nom "chouette"')
         self.assertEqual(len(rset.rows), 1, rset.rows)
 
     def test_select_nonregr_inlined(self):
-        self.execute("INSERT Note X: X para 'bidule'")
-        self.execute("INSERT Personne X: X nom 'chouette'")
-        self.execute("INSERT Personne X: X nom 'autre'")
-        self.execute("SET X ecrit_par P WHERE X para 'bidule', P nom 'chouette'")
-        rset = self.execute('Any U,T ORDERBY T DESC WHERE U is CWUser, '
-                            'N ecrit_par U, N type T')#, {'x': self.ueid})
+        self.qexecute("INSERT Note X: X para 'bidule'")
+        self.qexecute("INSERT Personne X: X nom 'chouette'")
+        self.qexecute("INSERT Personne X: X nom 'autre'")
+        self.qexecute("SET X ecrit_par P WHERE X para 'bidule', P nom 'chouette'")
+        rset = self.qexecute('Any U,T ORDERBY T DESC WHERE U is CWUser, '
+                             'N ecrit_par U, N type T')#, {'x': self.ueid})
         self.assertEqual(len(rset.rows), 0)
 
     def test_select_nonregr_edition_not(self):
         groupeids = set((2, 3, 4))
-        groupreadperms = set(r[0] for r in self.execute('Any Y WHERE X name "CWGroup", Y eid IN(2, 3, 4), X read_permission Y'))
-        rset = self.execute('DISTINCT Any Y WHERE X is CWEType, X name "CWGroup", Y eid IN(2, 3, 4), NOT X read_permission Y')
+        groupreadperms = set(r[0] for r in self.qexecute('Any Y WHERE X name "CWGroup", '
+                                                         'Y eid IN(2, 3, 4), X read_permission Y'))
+        rset = self.qexecute('DISTINCT Any Y WHERE X is CWEType, X name "CWGroup", '
+                             'Y eid IN(2, 3, 4), NOT X read_permission Y')
         self.assertEqual(sorted(r[0] for r in rset.rows), sorted(groupeids - groupreadperms))
-        rset = self.execute('DISTINCT Any Y WHERE X name "CWGroup", Y eid IN(2, 3, 4), NOT X read_permission Y')
+        rset = self.qexecute('DISTINCT Any Y WHERE X name "CWGroup", '
+                             'Y eid IN(2, 3, 4), NOT X read_permission Y')
         self.assertEqual(sorted(r[0] for r in rset.rows), sorted(groupeids - groupreadperms))
 
     def test_select_outer_join(self):
-        peid1 = self.execute("INSERT Personne X: X nom 'bidule'")[0][0]
-        peid2 = self.execute("INSERT Personne X: X nom 'autre'")[0][0]
-        seid1 = self.execute("INSERT Societe X: X nom 'chouette'")[0][0]
-        seid2 = self.execute("INSERT Societe X: X nom 'chouetos'")[0][0]
-        rset = self.execute('Any X,S ORDERBY X WHERE X travaille S?')
+        peid1 = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0]
+        peid2 = self.qexecute("INSERT Personne X: X nom 'autre'")[0][0]
+        seid1 = self.qexecute("INSERT Societe X: X nom 'chouette'")[0][0]
+        seid2 = self.qexecute("INSERT Societe X: X nom 'chouetos'")[0][0]
+        rset = self.qexecute('Any X,S ORDERBY X WHERE X travaille S?')
         self.assertEqual(rset.rows, [[peid1, None], [peid2, None]])
-        self.execute("SET P travaille S WHERE P nom 'bidule', S nom 'chouette'")
-        rset = self.execute('Any X,S ORDERBY X WHERE X travaille S?')
+        self.qexecute("SET P travaille S WHERE P nom 'bidule', S nom 'chouette'")
+        rset = self.qexecute('Any X,S ORDERBY X WHERE X travaille S?')
         self.assertEqual(rset.rows, [[peid1, seid1], [peid2, None]])
-        rset = self.execute('Any S,X ORDERBY S WHERE X? travaille S')
+        rset = self.qexecute('Any S,X ORDERBY S WHERE X? travaille S')
         self.assertEqual(rset.rows, [[seid1, peid1], [seid2, None]])
 
     def test_select_outer_join_optimized(self):
-        peid1 = self.execute("INSERT Personne X: X nom 'bidule'")[0][0]
-        rset = self.execute('Any X WHERE X eid %(x)s, P? connait X', {'x':peid1})
+        peid1 = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0]
+        rset = self.qexecute('Any X WHERE X eid %(x)s, P? connait X', {'x':peid1})
         self.assertEqual(rset.rows, [[peid1]])
-        rset = self.execute('Any X WHERE X eid %(x)s, X require_permission P?',
+        rset = self.qexecute('Any X WHERE X eid %(x)s, X require_permission P?',
                             {'x':peid1})
         self.assertEqual(rset.rows, [[peid1]])
 
     def test_select_left_outer_join(self):
-        rset = self.execute('DISTINCT Any G WHERE U? in_group G')
+        rset = self.qexecute('DISTINCT Any G WHERE U? in_group G')
         self.assertEqual(len(rset), 4)
-        rset = self.execute('DISTINCT Any G WHERE U? in_group G, U eid %(x)s',
+        rset = self.qexecute('DISTINCT Any G WHERE U? in_group G, U eid %(x)s',
                             {'x': self.session.user.eid})
         self.assertEqual(len(rset), 4)
 
     def test_select_ambigous_outer_join(self):
-        teid = self.execute("INSERT Tag X: X name 'tag'")[0][0]
-        self.execute("INSERT Tag X: X name 'tagbis'")[0][0]
-        geid = self.execute("CWGroup G WHERE G name 'users'")[0][0]
-        self.execute("SET X tags Y WHERE X eid %(t)s, Y eid %(g)s",
+        teid = self.qexecute("INSERT Tag X: X name 'tag'")[0][0]
+        self.qexecute("INSERT Tag X: X name 'tagbis'")[0][0]
+        geid = self.qexecute("CWGroup G WHERE G name 'users'")[0][0]
+        self.qexecute("SET X tags Y WHERE X eid %(t)s, Y eid %(g)s",
                      {'g': geid, 't': teid})
-        rset = self.execute("Any GN,TN ORDERBY GN WHERE T? tags G, T name TN, G name GN")
+        rset = self.qexecute("Any GN,TN ORDERBY GN WHERE T? tags G, T name TN, G name GN")
         self.assertIn(['users', 'tag'], rset.rows)
         self.assertIn(['activated', None], rset.rows)
-        rset = self.execute("Any GN,TN ORDERBY GN WHERE T tags G?, T name TN, G name GN")
+        rset = self.qexecute("Any GN,TN ORDERBY GN WHERE T tags G?, T name TN, G name GN")
         self.assertEqual(rset.rows, [[None, 'tagbis'], ['users', 'tag']])
 
     def test_select_not_inline_rel(self):
-        self.execute("INSERT Personne X: X nom 'bidule'")
-        self.execute("INSERT Note X: X type 'a'")
-        self.execute("INSERT Note X: X type 'b'")
-        self.execute("SET X ecrit_par Y WHERE X type 'a', Y nom 'bidule'")
-        rset = self.execute('Note X WHERE NOT X ecrit_par P')
+        self.qexecute("INSERT Personne X: X nom 'bidule'")
+        self.qexecute("INSERT Note X: X type 'a'")
+        self.qexecute("INSERT Note X: X type 'b'")
+        self.qexecute("SET X ecrit_par Y WHERE X type 'a', Y nom 'bidule'")
+        rset = self.qexecute('Note X WHERE NOT X ecrit_par P')
         self.assertEqual(len(rset.rows), 1, rset.rows)
 
     def test_select_not_unlinked_multiple_solutions(self):
-        self.execute("INSERT Personne X: X nom 'bidule'")
-        self.execute("INSERT Note X: X type 'a'")
-        self.execute("INSERT Note X: X type 'b'")
-        self.execute("SET Y evaluee X WHERE X type 'a', Y nom 'bidule'")
-        rset = self.execute('Note X WHERE NOT Y evaluee X')
+        self.qexecute("INSERT Personne X: X nom 'bidule'")
+        self.qexecute("INSERT Note X: X type 'a'")
+        self.qexecute("INSERT Note X: X type 'b'")
+        self.qexecute("SET Y evaluee X WHERE X type 'a', Y nom 'bidule'")
+        rset = self.qexecute('Note X WHERE NOT Y evaluee X')
         self.assertEqual(len(rset.rows), 1, rset.rows)
 
     def test_select_date_extraction(self):
-        self.execute("INSERT Personne X: X nom 'foo', X datenaiss %(d)s",
+        self.qexecute("INSERT Personne X: X nom 'foo', X datenaiss %(d)s",
                      {'d': datetime(2001, 2,3, 12,13)})
         test_data = [('YEAR', 2001), ('MONTH', 2), ('DAY', 3),
                      ('HOUR', 12), ('MINUTE', 13), ('WEEKDAY', 6)]
         for funcname, result in test_data:
-            rset = self.execute('Any %s(D) WHERE X is Personne, X datenaiss D'
+            rset = self.qexecute('Any %s(D) WHERE X is Personne, X datenaiss D'
                                 % funcname)
             self.assertEqual(len(rset.rows), 1)
             self.assertEqual(rset.rows[0][0], result)
             self.assertEqual(rset.description, [('Int',)])
 
     def test_regexp_based_pattern_matching(self):
-        peid1 = self.execute("INSERT Personne X: X nom 'bidule'")[0][0]
-        peid2 = self.execute("INSERT Personne X: X nom 'cidule'")[0][0]
-        rset = self.execute('Any X WHERE X is Personne, X nom REGEXP "^b"')
+        peid1 = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0]
+        peid2 = self.qexecute("INSERT Personne X: X nom 'cidule'")[0][0]
+        rset = self.qexecute('Any X WHERE X is Personne, X nom REGEXP "^b"')
         self.assertEqual(len(rset.rows), 1, rset.rows)
         self.assertEqual(rset.rows[0][0], peid1)
-        rset = self.execute('Any X WHERE X is Personne, X nom REGEXP "idu"')
+        rset = self.qexecute('Any X WHERE X is Personne, X nom REGEXP "idu"')
         self.assertEqual(len(rset.rows), 2, rset.rows)
 
     def test_select_aggregat_count(self):
-        rset = self.execute('Any COUNT(X)')
+        rset = self.qexecute('Any COUNT(X)')
         self.assertEqual(len(rset.rows), 1)
         self.assertEqual(len(rset.rows[0]), 1)
         self.assertEqual(rset.description, [('Int',)])
 
     def test_select_aggregat_sum(self):
-        rset = self.execute('Any SUM(O) WHERE X ordernum O')
+        rset = self.qexecute('Any SUM(O) WHERE X ordernum O')
         self.assertEqual(len(rset.rows), 1)
         self.assertEqual(len(rset.rows[0]), 1)
         self.assertEqual(rset.description, [('Int',)])
 
     def test_select_aggregat_min(self):
-        rset = self.execute('Any MIN(X) WHERE X is Personne')
+        rset = self.qexecute('Any MIN(X) WHERE X is Personne')
         self.assertEqual(len(rset.rows), 1)
         self.assertEqual(len(rset.rows[0]), 1)
         self.assertEqual(rset.description, [('Personne',)])
-        rset = self.execute('Any MIN(O) WHERE X ordernum O')
+        rset = self.qexecute('Any MIN(O) WHERE X ordernum O')
         self.assertEqual(len(rset.rows), 1)
         self.assertEqual(len(rset.rows[0]), 1)
         self.assertEqual(rset.description, [('Int',)])
 
     def test_select_aggregat_max(self):
-        rset = self.execute('Any MAX(X) WHERE X is Personne')
+        rset = self.qexecute('Any MAX(X) WHERE X is Personne')
         self.assertEqual(len(rset.rows), 1)
         self.assertEqual(len(rset.rows[0]), 1)
         self.assertEqual(rset.description, [('Personne',)])
-        rset = self.execute('Any MAX(O) WHERE X ordernum O')
+        rset = self.qexecute('Any MAX(O) WHERE X ordernum O')
         self.assertEqual(len(rset.rows), 1)
         self.assertEqual(len(rset.rows[0]), 1)
         self.assertEqual(rset.description, [('Int',)])
 
     def test_select_custom_aggregat_concat_string(self):
-        rset = self.execute('Any GROUP_CONCAT(N) WHERE X is CWGroup, X name N')
+        rset = self.qexecute('Any GROUP_CONCAT(N) WHERE X is CWGroup, X name N')
         self.assertTrue(rset)
         self.assertEqual(sorted(rset[0][0].split(', ')), ['guests', 'managers',
                                                              'owners', 'users'])
 
     def test_select_custom_regproc_limit_size(self):
-        rset = self.execute('Any TEXT_LIMIT_SIZE(N, 3) WHERE X is CWGroup, X name N, X name "managers"')
+        rset = self.qexecute('Any TEXT_LIMIT_SIZE(N, 3) WHERE X is CWGroup, X name N, X name "managers"')
         self.assertTrue(rset)
         self.assertEqual(rset[0][0], 'man...')
-        self.execute("INSERT Basket X: X name 'bidule', X description '<b>hop hop</b>', X description_format 'text/html'")
-        rset = self.execute('Any LIMIT_SIZE(D, DF, 3) WHERE X is Basket, X description D, X description_format DF')
+        self.qexecute("INSERT Basket X: X name 'bidule', X description '<b>hop hop</b>', X description_format 'text/html'")
+        rset = self.qexecute('Any LIMIT_SIZE(D, DF, 3) WHERE X is Basket, X description D, X description_format DF')
         self.assertTrue(rset)
         self.assertEqual(rset[0][0], 'hop...')
 
     def test_select_regproc_orderby(self):
-        rset = self.execute('DISTINCT Any X,N ORDERBY GROUP_SORT_VALUE(N) WHERE X is CWGroup, X name N, X name "managers"')
+        rset = self.qexecute('DISTINCT Any X,N ORDERBY GROUP_SORT_VALUE(N) WHERE X is CWGroup, X name N, X name "managers"')
         self.assertEqual(len(rset), 1)
         self.assertEqual(rset[0][1], 'managers')
-        rset = self.execute('Any X,N ORDERBY GROUP_SORT_VALUE(N) WHERE X is CWGroup, X name N, NOT U in_group X, U login "admin"')
+        rset = self.qexecute('Any X,N ORDERBY GROUP_SORT_VALUE(N) WHERE X is CWGroup, X name N, NOT U in_group X, U login "admin"')
         self.assertEqual(len(rset), 3)
         self.assertEqual(rset[0][1], 'owners')
 
     def test_select_aggregat_sort(self):
-        rset = self.execute('Any G, COUNT(U) GROUPBY G ORDERBY 2 WHERE U in_group G')
+        rset = self.qexecute('Any G, COUNT(U) GROUPBY G ORDERBY 2 WHERE U in_group G')
         self.assertEqual(len(rset.rows), 2)
         self.assertEqual(len(rset.rows[0]), 2)
         self.assertEqual(rset.description[0], ('CWGroup', 'Int',))
 
     def test_select_aggregat_having(self):
-        rset = self.execute('Any N,COUNT(RDEF) GROUPBY N ORDERBY 2,N '
+        rset = self.qexecute('Any N,COUNT(RDEF) GROUPBY N ORDERBY 2,N '
                             'WHERE RT name N, RDEF relation_type RT '
                             'HAVING COUNT(RDEF) > 10')
         self.assertListEqual(rset.rows,
@@ -577,21 +617,21 @@
 
     def test_select_aggregat_having_dumb(self):
         # dumb but should not raise an error
-        rset = self.execute('Any U,COUNT(X) GROUPBY U '
+        rset = self.qexecute('Any U,COUNT(X) GROUPBY U '
                             'WHERE U eid %(x)s, X owned_by U '
                             'HAVING COUNT(X) > 10', {'x': self.ueid})
         self.assertEqual(len(rset.rows), 1)
         self.assertEqual(rset.rows[0][0], self.ueid)
 
     def test_select_having_non_aggregat_1(self):
-        rset = self.execute('Any L WHERE X login L, X creation_date CD '
+        rset = self.qexecute('Any L WHERE X login L, X creation_date CD '
                             'HAVING YEAR(CD) = %s' % date.today().year)
         self.assertListEqual(rset.rows,
                               [[u'admin'],
                                [u'anon']])
 
     def test_select_having_non_aggregat_2(self):
-        rset = self.execute('Any L GROUPBY L WHERE X login L, X in_group G, '
+        rset = self.qexecute('Any L GROUPBY L WHERE X login L, X in_group G, '
                             'X creation_date CD HAVING YEAR(CD) = %s OR COUNT(G) > 1'
                             % date.today().year)
         self.assertListEqual(rset.rows,
@@ -600,226 +640,225 @@
 
     def test_select_complex_sort(self):
         """need sqlite including http://www.sqlite.org/cvstrac/tktview?tn=3773 fix"""
-        rset = self.execute('Any X ORDERBY X,D LIMIT 5 WHERE X creation_date D')
+        rset = self.qexecute('Any X ORDERBY X,D LIMIT 5 WHERE X creation_date D')
         result = rset.rows
         result.sort()
         self.assertEqual(tuplify(result), [(1,), (2,), (3,), (4,), (5,)])
 
     def test_select_upper(self):
-        rset = self.execute('Any X, UPPER(L) ORDERBY L WHERE X is CWUser, X login L')
+        rset = self.qexecute('Any X, UPPER(L) ORDERBY L WHERE X is CWUser, X login L')
         self.assertEqual(len(rset.rows), 2)
         self.assertEqual(rset.rows[0][1], 'ADMIN')
         self.assertEqual(rset.description[0], ('CWUser', 'String',))
         self.assertEqual(rset.rows[1][1], 'ANON')
         self.assertEqual(rset.description[1], ('CWUser', 'String',))
         eid = rset.rows[0][0]
-        rset = self.execute('Any UPPER(L) WHERE X eid %s, X login L'%eid)
+        rset = self.qexecute('Any UPPER(L) WHERE X eid %s, X login L'%eid)
         self.assertEqual(rset.rows[0][0], 'ADMIN')
         self.assertEqual(rset.description, [('String',)])
 
     def test_select_float_abs(self):
         # test positive number
-        eid = self.execute('INSERT Affaire A: A invoiced %(i)s', {'i': 1.2})[0][0]
-        rset = self.execute('Any ABS(I) WHERE X eid %(x)s, X invoiced I', {'x': eid})
+        eid = self.qexecute('INSERT Affaire A: A invoiced %(i)s', {'i': 1.2})[0][0]
+        rset = self.qexecute('Any ABS(I) WHERE X eid %(x)s, X invoiced I', {'x': eid})
         self.assertEqual(rset.rows[0][0], 1.2)
         # test negative number
-        eid = self.execute('INSERT Affaire A: A invoiced %(i)s', {'i': -1.2})[0][0]
-        rset = self.execute('Any ABS(I) WHERE X eid %(x)s, X invoiced I', {'x': eid})
+        eid = self.qexecute('INSERT Affaire A: A invoiced %(i)s', {'i': -1.2})[0][0]
+        rset = self.qexecute('Any ABS(I) WHERE X eid %(x)s, X invoiced I', {'x': eid})
         self.assertEqual(rset.rows[0][0], 1.2)
 
     def test_select_int_abs(self):
         # test positive number
-        eid = self.execute('INSERT Affaire A: A duration %(d)s', {'d': 12})[0][0]
-        rset = self.execute('Any ABS(D) WHERE X eid %(x)s, X duration D', {'x': eid})
+        eid = self.qexecute('INSERT Affaire A: A duration %(d)s', {'d': 12})[0][0]
+        rset = self.qexecute('Any ABS(D) WHERE X eid %(x)s, X duration D', {'x': eid})
         self.assertEqual(rset.rows[0][0], 12)
         # test negative number
-        eid = self.execute('INSERT Affaire A: A duration %(d)s', {'d': -12})[0][0]
-        rset = self.execute('Any ABS(D) WHERE X eid %(x)s, X duration D', {'x': eid})
+        eid = self.qexecute('INSERT Affaire A: A duration %(d)s', {'d': -12})[0][0]
+        rset = self.qexecute('Any ABS(D) WHERE X eid %(x)s, X duration D', {'x': eid})
         self.assertEqual(rset.rows[0][0], 12)
 
 ##     def test_select_simplified(self):
 ##         ueid = self.session.user.eid
-##         rset = self.execute('Any L WHERE %s login L'%ueid)
+##         rset = self.qexecute('Any L WHERE %s login L'%ueid)
 ##         self.assertEqual(rset.rows[0][0], 'admin')
-##         rset = self.execute('Any L WHERE %(x)s login L', {'x':ueid})
+##         rset = self.qexecute('Any L WHERE %(x)s login L', {'x':ueid})
 ##         self.assertEqual(rset.rows[0][0], 'admin')
 
     def test_select_searchable_text_1(self):
-        rset = self.execute(u"INSERT Personne X: X nom 'bidüle'")
-        rset = self.execute(u"INSERT Societe X: X nom 'bidüle'")
-        rset = self.execute("INSERT Societe X: X nom 'chouette'")
-        self.commit()
-        rset = self.execute('Any X where X has_text %(text)s', {'text': u'bidüle'})
+        rset = self.qexecute(u"INSERT Personne X: X nom 'bidüle'")
+        rset = self.qexecute(u"INSERT Societe X: X nom 'bidüle'")
+        rset = self.qexecute("INSERT Societe X: X nom 'chouette'")
+        rset = self.qexecute('Any X where X has_text %(text)s', {'text': u'bidüle'})
         self.assertEqual(len(rset.rows), 2, rset.rows)
-        rset = self.execute(u'Any N where N has_text "bidüle"')
+        rset = self.qexecute(u'Any N where N has_text "bidüle"')
         self.assertEqual(len(rset.rows), 2, rset.rows)
         biduleeids = [r[0] for r in rset.rows]
-        rset = self.execute(u'Any N where NOT N has_text "bidüle"')
+        rset = self.qexecute(u'Any N where NOT N has_text "bidüle"')
         self.assertFalse([r[0] for r in rset.rows if r[0] in biduleeids])
         # duh?
-        rset = self.execute('Any X WHERE X has_text %(text)s', {'text': u'ça'})
+        rset = self.qexecute('Any X WHERE X has_text %(text)s', {'text': u'ça'})
 
     def test_select_searchable_text_2(self):
-        rset = self.execute("INSERT Personne X: X nom 'bidule'")
-        rset = self.execute("INSERT Personne X: X nom 'chouette'")
-        rset = self.execute("INSERT Societe X: X nom 'bidule'")
-        self.commit()
-        rset = self.execute('Personne N where N has_text "bidule"')
+        rset = self.qexecute("INSERT Personne X: X nom 'bidule'")
+        rset = self.qexecute("INSERT Personne X: X nom 'chouette'")
+        rset = self.qexecute("INSERT Societe X: X nom 'bidule'")
+        rset = self.qexecute('Personne N where N has_text "bidule"')
         self.assertEqual(len(rset.rows), 1, rset.rows)
 
     def test_select_searchable_text_3(self):
-        rset = self.execute("INSERT Personne X: X nom 'bidule', X sexe 'M'")
-        rset = self.execute("INSERT Personne X: X nom 'bidule', X sexe 'F'")
-        rset = self.execute("INSERT Societe X: X nom 'bidule'")
-        self.commit()
-        rset = self.execute('Any X where X has_text "bidule" and X sexe "M"')
+        rset = self.qexecute("INSERT Personne X: X nom 'bidule', X sexe 'M'")
+        rset = self.qexecute("INSERT Personne X: X nom 'bidule', X sexe 'F'")
+        rset = self.qexecute("INSERT Societe X: X nom 'bidule'")
+        rset = self.qexecute('Any X where X has_text "bidule" and X sexe "M"')
         self.assertEqual(len(rset.rows), 1, rset.rows)
 
     def test_select_multiple_searchable_text(self):
-        self.execute(u"INSERT Personne X: X nom 'bidüle'")
-        self.execute("INSERT Societe X: X nom 'chouette', S travaille X")
-        self.execute(u"INSERT Personne X: X nom 'bidüle'")
-        self.commit()
-        rset = self.execute('Personne X WHERE X has_text %(text)s, X travaille S, S has_text %(text2)s',
+        self.qexecute(u"INSERT Personne X: X nom 'bidüle'")
+        self.qexecute("INSERT Societe X: X nom 'chouette', S travaille X")
+        self.qexecute(u"INSERT Personne X: X nom 'bidüle'")
+        rset = self.qexecute('Personne X WHERE X has_text %(text)s, X travaille S, S has_text %(text2)s',
                             {'text': u'bidüle',
                              'text2': u'chouette',}
                             )
         self.assertEqual(len(rset.rows), 1, rset.rows)
 
     def test_select_no_descr(self):
-        rset = self.execute('Any X WHERE X is CWGroup', build_descr=0)
+        rset = self.qexecute('Any X WHERE X is CWGroup', build_descr=0)
         rset.rows.sort()
         self.assertEqual(tuplify(rset.rows), [(2,), (3,), (4,), (5,)])
         self.assertEqual(rset.description, ())
 
     def test_select_limit_offset(self):
-        rset = self.execute('CWGroup X ORDERBY N LIMIT 2 WHERE X name N')
+        rset = self.qexecute('CWGroup X ORDERBY N LIMIT 2 WHERE X name N')
         self.assertEqual(tuplify(rset.rows), [(2,), (3,)])
         self.assertEqual(rset.description, [('CWGroup',), ('CWGroup',)])
-        rset = self.execute('CWGroup X ORDERBY N LIMIT 2 OFFSET 2 WHERE X name N')
+        rset = self.qexecute('CWGroup X ORDERBY N LIMIT 2 OFFSET 2 WHERE X name N')
         self.assertEqual(tuplify(rset.rows), [(4,), (5,)])
 
     def test_select_symmetric(self):
-        self.execute("INSERT Personne X: X nom 'machin'")
-        self.execute("INSERT Personne X: X nom 'bidule'")
-        self.execute("INSERT Personne X: X nom 'chouette'")
-        self.execute("INSERT Personne X: X nom 'trucmuche'")
-        self.execute("SET X connait Y WHERE X nom 'chouette', Y nom 'bidule'")
-        self.execute("SET X connait Y WHERE X nom 'machin', Y nom 'chouette'")
-        rset = self.execute('Any P WHERE P connait P2')
+        self.qexecute("INSERT Personne X: X nom 'machin'")
+        self.qexecute("INSERT Personne X: X nom 'bidule'")
+        self.qexecute("INSERT Personne X: X nom 'chouette'")
+        self.qexecute("INSERT Personne X: X nom 'trucmuche'")
+        self.qexecute("SET X connait Y WHERE X nom 'chouette', Y nom 'bidule'")
+        self.qexecute("SET X connait Y WHERE X nom 'machin', Y nom 'chouette'")
+        rset = self.qexecute('Any P WHERE P connait P2')
         self.assertEqual(len(rset.rows), 4, rset.rows)
-        rset = self.execute('Any P WHERE NOT P connait P2')
+        rset = self.qexecute('Any P WHERE NOT P connait P2')
         self.assertEqual(len(rset.rows), 1, rset.rows) # trucmuche
-        rset = self.execute('Any P WHERE P connait P2, P2 nom "bidule"')
+        rset = self.qexecute('Any P WHERE P connait P2, P2 nom "bidule"')
         self.assertEqual(len(rset.rows), 1, rset.rows)
-        rset = self.execute('Any P WHERE P2 connait P, P2 nom "bidule"')
+        rset = self.qexecute('Any P WHERE P2 connait P, P2 nom "bidule"')
         self.assertEqual(len(rset.rows), 1, rset.rows)
-        rset = self.execute('Any P WHERE P connait P2, P2 nom "chouette"')
+        rset = self.qexecute('Any P WHERE P connait P2, P2 nom "chouette"')
         self.assertEqual(len(rset.rows), 2, rset.rows)
-        rset = self.execute('Any P WHERE P2 connait P, P2 nom "chouette"')
+        rset = self.qexecute('Any P WHERE P2 connait P, P2 nom "chouette"')
         self.assertEqual(len(rset.rows), 2, rset.rows)
 
     def test_select_inline(self):
-        self.execute("INSERT Personne X: X nom 'bidule'")
-        self.execute("INSERT Note X: X type 'a'")
-        self.execute("SET X ecrit_par Y WHERE X type 'a', Y nom 'bidule'")
-        rset = self.execute('Any N where N ecrit_par X, X nom "bidule"')
+        self.qexecute("INSERT Personne X: X nom 'bidule'")
+        self.qexecute("INSERT Note X: X type 'a'")
+        self.qexecute("SET X ecrit_par Y WHERE X type 'a', Y nom 'bidule'")
+        rset = self.qexecute('Any N where N ecrit_par X, X nom "bidule"')
         self.assertEqual(len(rset.rows), 1, rset.rows)
 
     def test_select_creation_date(self):
-        self.execute("INSERT Personne X: X nom 'bidule'")
-        rset = self.execute('Any D WHERE X nom "bidule", X creation_date D')
+        self.qexecute("INSERT Personne X: X nom 'bidule'")
+        rset = self.qexecute('Any D WHERE X nom "bidule", X creation_date D')
         self.assertEqual(len(rset.rows), 1)
 
     def test_select_or_relation(self):
-        self.execute("INSERT Personne X: X nom 'bidule'")
-        self.execute("INSERT Personne X: X nom 'chouette'")
-        self.execute("INSERT Societe X: X nom 'logilab'")
-        self.execute("INSERT Societe X: X nom 'caesium'")
-        self.execute("SET P travaille S WHERE P nom 'bidule', S nom 'logilab'")
-        rset = self.execute('DISTINCT Any P WHERE P travaille S1 OR P travaille S2, S1 nom "logilab", S2 nom "caesium"')
+        self.qexecute("INSERT Personne X: X nom 'bidule'")
+        self.qexecute("INSERT Personne X: X nom 'chouette'")
+        self.qexecute("INSERT Societe X: X nom 'logilab'")
+        self.qexecute("INSERT Societe X: X nom 'caesium'")
+        self.qexecute("SET P travaille S WHERE P nom 'bidule', S nom 'logilab'")
+        rset = self.qexecute('DISTINCT Any P WHERE P travaille S1 OR P travaille S2, '
+                             'S1 nom "logilab", S2 nom "caesium"')
         self.assertEqual(len(rset.rows), 1)
-        self.execute("SET P travaille S WHERE P nom 'chouette', S nom 'caesium'")
-        rset = self.execute('DISTINCT Any P WHERE P travaille S1 OR P travaille S2, S1 nom "logilab", S2 nom "caesium"')
+        self.qexecute("SET P travaille S WHERE P nom 'chouette', S nom 'caesium'")
+        rset = self.qexecute('DISTINCT Any P WHERE P travaille S1 OR P travaille S2, '
+                             'S1 nom "logilab", S2 nom "caesium"')
         self.assertEqual(len(rset.rows), 2)
 
     def test_select_or_sym_relation(self):
-        self.execute("INSERT Personne X: X nom 'bidule'")
-        self.execute("INSERT Personne X: X nom 'chouette'")
-        self.execute("INSERT Personne X: X nom 'truc'")
-        self.execute("SET P connait S WHERE P nom 'bidule', S nom 'chouette'")
-        rset = self.execute('DISTINCT Any P WHERE S connait P, S nom "chouette"')
+        self.qexecute("INSERT Personne X: X nom 'bidule'")
+        self.qexecute("INSERT Personne X: X nom 'chouette'")
+        self.qexecute("INSERT Personne X: X nom 'truc'")
+        self.qexecute("SET P connait S WHERE P nom 'bidule', S nom 'chouette'")
+        rset = self.qexecute('DISTINCT Any P WHERE S connait P, S nom "chouette"')
         self.assertEqual(len(rset.rows), 1, rset.rows)
-        rset = self.execute('DISTINCT Any P WHERE P connait S or S connait P, S nom "chouette"')
+        rset = self.qexecute('DISTINCT Any P WHERE P connait S or S connait P, S nom "chouette"')
         self.assertEqual(len(rset.rows), 1, rset.rows)
-        self.execute("SET P connait S WHERE P nom 'chouette', S nom 'truc'")
-        rset = self.execute('DISTINCT Any P WHERE S connait P, S nom "chouette"')
+        self.qexecute("SET P connait S WHERE P nom 'chouette', S nom 'truc'")
+        rset = self.qexecute('DISTINCT Any P WHERE S connait P, S nom "chouette"')
         self.assertEqual(len(rset.rows), 2, rset.rows)
-        rset = self.execute('DISTINCT Any P WHERE P connait S OR S connait P, S nom "chouette"')
+        rset = self.qexecute('DISTINCT Any P WHERE P connait S OR S connait P, S nom "chouette"')
         self.assertEqual(len(rset.rows), 2, rset.rows)
 
     def test_select_follow_relation(self):
-        self.execute("INSERT Affaire X: X sujet 'cool'")
-        self.execute("INSERT Societe X: X nom 'chouette'")
-        self.execute("SET A concerne S WHERE A is Affaire, S is Societe")
-        self.execute("INSERT Note X: X para 'truc'")
-        self.execute("SET S evaluee N WHERE S is Societe, N is Note")
-        self.execute("INSERT Societe X: X nom 'bidule'")
-        self.execute("INSERT Note X: X para 'troc'")
-        self.execute("SET S evaluee N WHERE S nom 'bidule', N para 'troc'")
-        rset = self.execute('DISTINCT Any A,N WHERE A concerne S, S evaluee N')
+        self.qexecute("INSERT Affaire X: X sujet 'cool'")
+        self.qexecute("INSERT Societe X: X nom 'chouette'")
+        self.qexecute("SET A concerne S WHERE A is Affaire, S is Societe")
+        self.qexecute("INSERT Note X: X para 'truc'")
+        self.qexecute("SET S evaluee N WHERE S is Societe, N is Note")
+        self.qexecute("INSERT Societe X: X nom 'bidule'")
+        self.qexecute("INSERT Note X: X para 'troc'")
+        self.qexecute("SET S evaluee N WHERE S nom 'bidule', N para 'troc'")
+        rset = self.qexecute('DISTINCT Any A,N WHERE A concerne S, S evaluee N')
         self.assertEqual(len(rset.rows), 1, rset.rows)
 
     def test_select_ordered_distinct_1(self):
         self.assertRaises(BadRQLQuery,
-                          self.execute, 'DISTINCT Any S ORDERBY R WHERE A is Affaire, A sujet S, A ref R')
+                          self.qexecute, 'DISTINCT Any S ORDERBY R WHERE A is Affaire, A sujet S, A ref R')
 
     def test_select_ordered_distinct_2(self):
-        self.execute("INSERT Affaire X: X sujet 'minor'")
-        self.execute("INSERT Affaire X: X sujet 'zou'")
-        self.execute("INSERT Affaire X: X sujet 'abcd'")
-        rset = self.execute('DISTINCT Any S ORDERBY S WHERE A is Affaire, A sujet S')
+        self.qexecute("INSERT Affaire X: X sujet 'minor'")
+        self.qexecute("INSERT Affaire X: X sujet 'zou'")
+        self.qexecute("INSERT Affaire X: X sujet 'abcd'")
+        rset = self.qexecute('DISTINCT Any S ORDERBY S WHERE A is Affaire, A sujet S')
         self.assertEqual(rset.rows, [['abcd'], ['minor'], ['zou']])
 
     def test_select_ordered_distinct_3(self):
-        rset = self.execute('DISTINCT Any N ORDERBY GROUP_SORT_VALUE(N) WHERE X is CWGroup, X name N')
+        rset = self.qexecute('DISTINCT Any N ORDERBY GROUP_SORT_VALUE(N) WHERE X is CWGroup, X name N')
         self.assertEqual(rset.rows, [['owners'], ['guests'], ['users'], ['managers']])
 
     def test_select_or_value(self):
-        rset = self.execute('Any U WHERE U in_group G, G name "owners" OR G name "users"')
+        rset = self.qexecute('Any U WHERE U in_group G, G name "owners" OR G name "users"')
         self.assertEqual(len(rset.rows), 0)
-        rset = self.execute('Any U WHERE U in_group G, G name "guests" OR G name "managers"')
+        rset = self.qexecute('Any U WHERE U in_group G, G name "guests" OR G name "managers"')
         self.assertEqual(len(rset.rows), 2)
 
     def test_select_explicit_eid(self):
-        rset = self.execute('Any X,E WHERE X owned_by U, X eid E, U eid %(u)s', {'u': self.session.user.eid})
+        rset = self.qexecute('Any X,E WHERE X owned_by U, X eid E, U eid %(u)s',
+                             {'u': self.session.user.eid})
         self.assertTrue(rset)
         self.assertEqual(rset.description[0][1], 'Int')
 
 #     def test_select_rewritten_optional(self):
-#         eid = self.execute("INSERT Affaire X: X sujet 'cool'")[0][0]
-#         rset = self.execute('Any X WHERE X eid %(x)s, EXISTS(X owned_by U) OR EXISTS(X concerne S?, S owned_by U)',
+#         eid = self.qexecute("INSERT Affaire X: X sujet 'cool'")[0][0]
+#         rset = self.qexecute('Any X WHERE X eid %(x)s, EXISTS(X owned_by U) OR EXISTS(X concerne S?, S owned_by U)',
 #                             {'x': eid}, 'x')
 #         self.assertEqual(rset.rows, [[eid]])
 
     def test_today_bug(self):
-        self.execute("INSERT Tag X: X name 'bidule', X creation_date NOW")
-        self.execute("INSERT Tag Y: Y name 'toto'")
-        rset = self.execute("Any D WHERE X name in ('bidule', 'toto') , X creation_date D")
+        self.qexecute("INSERT Tag X: X name 'bidule', X creation_date NOW")
+        self.qexecute("INSERT Tag Y: Y name 'toto'")
+        rset = self.qexecute("Any D WHERE X name in ('bidule', 'toto') , X creation_date D")
         self.assertIsInstance(rset.rows[0][0], datetime)
-        rset = self.execute('Tag X WHERE X creation_date TODAY')
+        rset = self.qexecute('Tag X WHERE X creation_date TODAY')
         self.assertEqual(len(rset.rows), 2)
-        rset = self.execute('Any MAX(D) WHERE X is Tag, X creation_date D')
+        rset = self.qexecute('Any MAX(D) WHERE X is Tag, X creation_date D')
         self.assertIsInstance(rset[0][0], datetime)
 
     def test_today(self):
-        self.execute("INSERT Tag X: X name 'bidule', X creation_date TODAY")
-        self.execute("INSERT Tag Y: Y name 'toto'")
-        rset = self.execute('Tag X WHERE X creation_date TODAY')
+        self.qexecute("INSERT Tag X: X name 'bidule', X creation_date TODAY")
+        self.qexecute("INSERT Tag Y: Y name 'toto'")
+        rset = self.qexecute('Tag X WHERE X creation_date TODAY')
         self.assertEqual(len(rset.rows), 2)
 
     def test_select_boolean(self):
-        rset = self.execute('Any N WHERE X is CWEType, X name N, X final %(val)s',
+        rset = self.qexecute('Any N WHERE X is CWEType, X name N, X final %(val)s',
                             {'val': True})
         self.assertEqual(sorted(r[0] for r in rset.rows), ['BigInt', 'Boolean', 'Bytes',
                                                            'Date', 'Datetime',
@@ -828,7 +867,7 @@
                                                            'Password', 'String',
                                                            'TZDatetime', 'TZTime',
                                                            'Time'])
-        rset = self.execute('Any N WHERE X is CWEType, X name N, X final TRUE')
+        rset = self.qexecute('Any N WHERE X is CWEType, X name N, X final TRUE')
         self.assertEqual(sorted(r[0] for r in rset.rows), ['BigInt', 'Boolean', 'Bytes',
                                                            'Date', 'Datetime',
                                                            'Decimal', 'Float',
@@ -836,32 +875,33 @@
                                                            'Password', 'String',
                                                            'TZDatetime', 'TZTime',
                                                            'Time'])
-        req = self.session
-        req.create_entity('Personne', nom=u'louis', test=True)
-        self.assertEqual(len(req.execute('Any X WHERE X test %(val)s', {'val': True})), 1)
-        self.assertEqual(len(req.execute('Any X WHERE X test TRUE')), 1)
-        self.assertEqual(len(req.execute('Any X WHERE X test %(val)s', {'val': False})), 0)
-        self.assertEqual(len(req.execute('Any X WHERE X test FALSE')), 0)
+        with self.session.new_cnx() as cnx:
+            cnx.create_entity('Personne', nom=u'louis', test=True)
+            self.assertEqual(len(cnx.execute('Any X WHERE X test %(val)s', {'val': True})), 1)
+            self.assertEqual(len(cnx.execute('Any X WHERE X test TRUE')), 1)
+            self.assertEqual(len(cnx.execute('Any X WHERE X test %(val)s', {'val': False})), 0)
+            self.assertEqual(len(cnx.execute('Any X WHERE X test FALSE')), 0)
 
     def test_select_constant(self):
-        rset = self.execute('Any X, "toto" ORDERBY X WHERE X is CWGroup')
+        rset = self.qexecute('Any X, "toto" ORDERBY X WHERE X is CWGroup')
         self.assertEqual(rset.rows,
                           map(list, zip((2,3,4,5), ('toto','toto','toto','toto',))))
         self.assertIsInstance(rset[0][1], unicode)
         self.assertEqual(rset.description,
                           zip(('CWGroup', 'CWGroup', 'CWGroup', 'CWGroup'),
                               ('String', 'String', 'String', 'String',)))
-        rset = self.execute('Any X, %(value)s ORDERBY X WHERE X is CWGroup', {'value': 'toto'})
+        rset = self.qexecute('Any X, %(value)s ORDERBY X WHERE X is CWGroup', {'value': 'toto'})
         self.assertEqual(rset.rows,
                           map(list, zip((2,3,4,5), ('toto','toto','toto','toto',))))
         self.assertIsInstance(rset[0][1], unicode)
         self.assertEqual(rset.description,
                           zip(('CWGroup', 'CWGroup', 'CWGroup', 'CWGroup'),
                               ('String', 'String', 'String', 'String',)))
-        rset = self.execute('Any X,GN WHERE X is CWUser, G is CWGroup, X login "syt", X in_group G, G name GN')
+        rset = self.qexecute('Any X,GN WHERE X is CWUser, G is CWGroup, X login "syt", '
+                             'X in_group G, G name GN')
 
     def test_select_union(self):
-        rset = self.execute('Any X,N ORDERBY N WITH X,N BEING '
+        rset = self.qexecute('Any X,N ORDERBY N WITH X,N BEING '
                             '((Any X,N WHERE X name N, X transition_of WF, WF workflow_of E, E name %(name)s)'
                             ' UNION '
                             '(Any X,N WHERE X name N, X state_of WF, WF workflow_of E, E name %(name)s))',
@@ -875,23 +915,26 @@
     def test_select_union_aggregat(self):
         # meaningless, the goal in to have group by done on different attribute
         # for each sub-query
-        self.execute('(Any N,COUNT(X) GROUPBY N WHERE X name N, X is State)'
+        self.qexecute('(Any N,COUNT(X) GROUPBY N WHERE X name N, X is State)'
                      ' UNION '
                      '(Any N,COUNT(X) GROUPBY N ORDERBY 2 WHERE X login N)')
 
     def test_select_union_aggregat_independant_group(self):
-        self.execute('INSERT State X: X name "hop"')
-        self.execute('INSERT State X: X name "hop"')
-        self.execute('INSERT Transition X: X name "hop"')
-        self.execute('INSERT Transition X: X name "hop"')
-        rset = self.execute('Any N,NX ORDERBY 2 WITH N,NX BEING '
-                            '((Any N,COUNT(X) GROUPBY N WHERE X name N, X is State HAVING COUNT(X)>1)'
-                            ' UNION '
-                            '(Any N,COUNT(X) GROUPBY N WHERE X name N, X is Transition HAVING COUNT(X)>1))')
-        self.assertEqual(rset.rows, [[u'hop', 2], [u'hop', 2]])
+        with self.session.new_cnx() as cnx:
+            cnx.execute('INSERT State X: X name "hop"')
+            cnx.execute('INSERT State X: X name "hop"')
+            cnx.execute('INSERT Transition X: X name "hop"')
+            cnx.execute('INSERT Transition X: X name "hop"')
+            rset = cnx.execute('Any N,NX ORDERBY 2 WITH N,NX BEING '
+                               '((Any N,COUNT(X) GROUPBY N WHERE X name N, '
+                               '  X is State HAVING COUNT(X)>1)'
+                               ' UNION '
+                               '(Any N,COUNT(X) GROUPBY N WHERE X name N, '
+                               ' X is Transition HAVING COUNT(X)>1))')
+            self.assertEqual(rset.rows, [[u'hop', 2], [u'hop', 2]])
 
     def test_select_union_selection_with_diff_variables(self):
-        rset = self.execute('(Any N WHERE X name N, X is State)'
+        rset = self.qexecute('(Any N WHERE X name N, X is State)'
                             ' UNION '
                             '(Any NN WHERE XX name NN, XX is Transition)')
         self.assertEqual(sorted(r[0] for r in rset.rows),
@@ -901,51 +944,51 @@
                            'start', 'todo'])
 
     def test_select_union_description_diff_var(self):
-        eid1 = self.execute('CWGroup X WHERE X name "managers"')[0][0]
-        eid2 = self.execute('CWUser X WHERE X login "admin"')[0][0]
-        rset = self.execute('(Any X WHERE X eid %(x)s)'
+        eid1 = self.qexecute('CWGroup X WHERE X name "managers"')[0][0]
+        eid2 = self.qexecute('CWUser X WHERE X login "admin"')[0][0]
+        rset = self.qexecute('(Any X WHERE X eid %(x)s)'
                             ' UNION '
                             '(Any Y WHERE Y eid %(y)s)',
                             {'x': eid1, 'y': eid2})
         self.assertEqual(rset.description[:], [('CWGroup',), ('CWUser',)])
 
     def test_exists(self):
-        geid = self.execute("INSERT CWGroup X: X name 'lulufanclub'")[0][0]
-        self.execute("SET U in_group G WHERE G name 'lulufanclub'")
-        peid = self.execute("INSERT Personne X: X prenom 'lulu', X nom 'petit'")[0][0]
-        rset = self.execute("Any X WHERE X prenom 'lulu',"
+        geid = self.qexecute("INSERT CWGroup X: X name 'lulufanclub'")[0][0]
+        self.qexecute("SET U in_group G WHERE G name 'lulufanclub'")
+        peid = self.qexecute("INSERT Personne X: X prenom 'lulu', X nom 'petit'")[0][0]
+        rset = self.qexecute("Any X WHERE X prenom 'lulu',"
                             "EXISTS (U in_group G, G name 'lulufanclub' OR G name 'managers');")
         self.assertEqual(rset.rows, [[peid]])
 
     def test_identity(self):
-        eid = self.execute('Any X WHERE X identity Y, Y eid 1')[0][0]
+        eid = self.qexecute('Any X WHERE X identity Y, Y eid 1')[0][0]
         self.assertEqual(eid, 1)
-        eid = self.execute('Any X WHERE Y identity X, Y eid 1')[0][0]
+        eid = self.qexecute('Any X WHERE Y identity X, Y eid 1')[0][0]
         self.assertEqual(eid, 1)
-        login = self.execute('Any L WHERE X login "admin", X identity Y, Y login L')[0][0]
+        login = self.qexecute('Any L WHERE X login "admin", X identity Y, Y login L')[0][0]
         self.assertEqual(login, 'admin')
 
     def test_select_date_mathexp(self):
-        rset = self.execute('Any X, TODAY - CD WHERE X is CWUser, X creation_date CD')
+        rset = self.qexecute('Any X, TODAY - CD WHERE X is CWUser, X creation_date CD')
         self.assertTrue(rset)
         self.assertEqual(rset.description[0][1], 'Interval')
-        eid, = self.execute("INSERT Personne X: X nom 'bidule'")[0]
-        rset = self.execute('Any X, NOW - CD WHERE X is Personne, X creation_date CD')
+        eid, = self.qexecute("INSERT Personne X: X nom 'bidule'")[0]
+        rset = self.qexecute('Any X, NOW - CD WHERE X is Personne, X creation_date CD')
         self.assertEqual(rset.description[0][1], 'Interval')
 
     def test_select_subquery_aggregat_1(self):
         # percent users by groups
-        self.execute('SET X in_group G WHERE G name "users"')
-        rset = self.execute('Any GN, COUNT(X)*100/T GROUPBY GN ORDERBY 2,1'
+        self.qexecute('SET X in_group G WHERE G name "users"')
+        rset = self.qexecute('Any GN, COUNT(X)*100/T GROUPBY GN ORDERBY 2,1'
                             ' WHERE G name GN, X in_group G'
                             ' WITH T BEING (Any COUNT(U) WHERE U is CWUser)')
         self.assertEqual(rset.rows, [[u'guests', 50], [u'managers', 50], [u'users', 100]])
         self.assertEqual(rset.description, [('String', 'Int'), ('String', 'Int'), ('String', 'Int')])
 
     def test_select_subquery_aggregat_2(self):
-        expected = self.execute('Any X, 0, COUNT(T) GROUPBY X '
+        expected = self.qexecute('Any X, 0, COUNT(T) GROUPBY X '
                                 'WHERE X is Workflow, T transition_of X').rows
-        rset = self.execute('''
+        rset = self.qexecute('''
 Any P1,B,E WHERE P1 identity P2 WITH
   P1,B BEING (Any P,COUNT(T) GROUPBY P WHERE P is Workflow, T is Transition,
               T? transition_of P, T type "auto"),
@@ -954,116 +997,120 @@
         self.assertEqual(sorted(rset.rows), sorted(expected))
 
     def test_select_subquery_const(self):
-        rset = self.execute('Any X WITH X BEING ((Any NULL) UNION (Any "toto"))')
+        rset = self.qexecute('Any X WITH X BEING ((Any NULL) UNION (Any "toto"))')
         self.assertEqual(rset.rows, [[None], ['toto']])
         self.assertEqual(rset.description, [(None,), ('String',)])
 
     # insertion queries tests #################################################
 
     def test_insert_is(self):
-        eid, = self.execute("INSERT Personne X: X nom 'bidule'")[0]
-        etype, = self.execute("Any TN WHERE X is T, X eid %s, T name TN" % eid)[0]
+        eid, = self.qexecute("INSERT Personne X: X nom 'bidule'")[0]
+        etype, = self.qexecute("Any TN WHERE X is T, X eid %s, T name TN" % eid)[0]
         self.assertEqual(etype, 'Personne')
-        self.execute("INSERT Personne X: X nom 'managers'")
+        self.qexecute("INSERT Personne X: X nom 'managers'")
 
     def test_insert_1(self):
-        rset = self.execute("INSERT Personne X: X nom 'bidule'")
+        rset = self.qexecute("INSERT Personne X: X nom 'bidule'")
         self.assertEqual(len(rset.rows), 1)
         self.assertEqual(rset.description, [('Personne',)])
-        rset = self.execute('Personne X WHERE X nom "bidule"')
+        rset = self.qexecute('Personne X WHERE X nom "bidule"')
         self.assert_(rset.rows)
         self.assertEqual(rset.description, [('Personne',)])
 
     def test_insert_1_multiple(self):
-        self.execute("INSERT Personne X: X nom 'bidule'")
-        self.execute("INSERT Personne X: X nom 'chouette'")
-        rset = self.execute("INSERT Societe Y: Y nom N, P travaille Y WHERE P nom N")
+        self.qexecute("INSERT Personne X: X nom 'bidule'")
+        self.qexecute("INSERT Personne X: X nom 'chouette'")
+        rset = self.qexecute("INSERT Societe Y: Y nom N, P travaille Y WHERE P nom N")
         self.assertEqual(len(rset.rows), 2)
         self.assertEqual(rset.description, [('Societe',), ('Societe',)])
 
     def test_insert_2(self):
-        rset = self.execute("INSERT Personne X, Personne Y: X nom 'bidule', Y nom 'tutu'")
+        rset = self.qexecute("INSERT Personne X, Personne Y: X nom 'bidule', Y nom 'tutu'")
         self.assertEqual(rset.description, [('Personne', 'Personne')])
-        rset = self.execute('Personne X WHERE X nom "bidule" or X nom "tutu"')
+        rset = self.qexecute('Personne X WHERE X nom "bidule" or X nom "tutu"')
         self.assert_(rset.rows)
         self.assertEqual(rset.description, [('Personne',), ('Personne',)])
 
     def test_insert_3(self):
-        self.execute("INSERT Personne X: X nom Y WHERE U login 'admin', U login Y")
-        rset = self.execute('Personne X WHERE X nom "admin"')
+        self.qexecute("INSERT Personne X: X nom Y WHERE U login 'admin', U login Y")
+        rset = self.qexecute('Personne X WHERE X nom "admin"')
         self.assert_(rset.rows)
         self.assertEqual(rset.description, [('Personne',)])
 
     def test_insert_4(self):
-        self.execute("INSERT Societe Y: Y nom 'toto'")
-        self.execute("INSERT Personne X: X nom 'bidule', X travaille Y WHERE Y nom 'toto'")
-        rset = self.execute('Any X, Y WHERE X nom "bidule", Y nom "toto", X travaille Y')
+        self.qexecute("INSERT Societe Y: Y nom 'toto'")
+        self.qexecute("INSERT Personne X: X nom 'bidule', X travaille Y WHERE Y nom 'toto'")
+        rset = self.qexecute('Any X, Y WHERE X nom "bidule", Y nom "toto", X travaille Y')
         self.assert_(rset.rows)
         self.assertEqual(rset.description, [('Personne', 'Societe',)])
 
     def test_insert_4bis(self):
-        peid = self.execute("INSERT Personne X: X nom 'bidule'")[0][0]
-        seid = self.execute("INSERT Societe Y: Y nom 'toto', X travaille Y WHERE X eid %(x)s",
+        peid = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0]
+        seid = self.qexecute("INSERT Societe Y: Y nom 'toto', X travaille Y WHERE X eid %(x)s",
                              {'x': str(peid)})[0][0]
-        self.assertEqual(len(self.execute('Any X, Y WHERE X travaille Y')), 1)
-        self.execute("INSERT Personne X: X nom 'chouette', X travaille Y WHERE Y eid %(x)s",
+        self.assertEqual(len(self.qexecute('Any X, Y WHERE X travaille Y')), 1)
+        self.qexecute("INSERT Personne X: X nom 'chouette', X travaille Y WHERE Y eid %(x)s",
                       {'x': str(seid)})
-        self.assertEqual(len(self.execute('Any X, Y WHERE X travaille Y')), 2)
+        self.assertEqual(len(self.qexecute('Any X, Y WHERE X travaille Y')), 2)
 
     def test_insert_4ter(self):
-        peid = self.execute("INSERT Personne X: X nom 'bidule'")[0][0]
-        seid = self.execute("INSERT Societe Y: Y nom 'toto', X travaille Y WHERE X eid %(x)s",
+        peid = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0]
+        seid = self.qexecute("INSERT Societe Y: Y nom 'toto', X travaille Y WHERE X eid %(x)s",
                              {'x': unicode(peid)})[0][0]
-        self.assertEqual(len(self.execute('Any X, Y WHERE X travaille Y')), 1)
-        self.execute("INSERT Personne X: X nom 'chouette', X travaille Y WHERE Y eid %(x)s",
+        self.assertEqual(len(self.qexecute('Any X, Y WHERE X travaille Y')), 1)
+        self.qexecute("INSERT Personne X: X nom 'chouette', X travaille Y WHERE Y eid %(x)s",
                       {'x': unicode(seid)})
-        self.assertEqual(len(self.execute('Any X, Y WHERE X travaille Y')), 2)
+        self.assertEqual(len(self.qexecute('Any X, Y WHERE X travaille Y')), 2)
 
     def test_insert_5(self):
-        self.execute("INSERT Personne X: X nom 'bidule'")
-        self.execute("INSERT Societe Y: Y nom 'toto', X travaille Y WHERE X nom 'bidule'")
-        rset = self.execute('Any X, Y WHERE X nom "bidule", Y nom "toto", X travaille Y')
+        self.qexecute("INSERT Personne X: X nom 'bidule'")
+        self.qexecute("INSERT Societe Y: Y nom 'toto', X travaille Y WHERE X nom 'bidule'")
+        rset = self.qexecute('Any X, Y WHERE X nom "bidule", Y nom "toto", X travaille Y')
         self.assert_(rset.rows)
         self.assertEqual(rset.description, [('Personne', 'Societe',)])
 
     def test_insert_5bis(self):
-        peid = self.execute("INSERT Personne X: X nom 'bidule'")[0][0]
-        self.execute("INSERT Societe Y: Y nom 'toto', X travaille Y WHERE X eid %(x)s",
+        peid = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0]
+        self.qexecute("INSERT Societe Y: Y nom 'toto', X travaille Y WHERE X eid %(x)s",
                      {'x': peid})
-        rset = self.execute('Any X, Y WHERE X nom "bidule", Y nom "toto", X travaille Y')
+        rset = self.qexecute('Any X, Y WHERE X nom "bidule", Y nom "toto", X travaille Y')
         self.assert_(rset.rows)
         self.assertEqual(rset.description, [('Personne', 'Societe',)])
 
     def test_insert_6(self):
-        self.execute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto', X travaille Y")
-        rset = self.execute('Any X, Y WHERE X nom "bidule", Y nom "toto", X travaille Y')
+        self.qexecute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto', X travaille Y")
+        rset = self.qexecute('Any X, Y WHERE X nom "bidule", Y nom "toto", X travaille Y')
         self.assert_(rset.rows)
         self.assertEqual(rset.description, [('Personne', 'Societe',)])
 
     def test_insert_7(self):
-        self.execute("INSERT Personne X, Societe Y: X nom N, Y nom 'toto', X travaille Y WHERE U login 'admin', U login N")
-        rset = self.execute('Any X, Y WHERE X nom "admin", Y nom "toto", X travaille Y')
+        self.qexecute("INSERT Personne X, Societe Y: X nom N, Y nom 'toto', "
+                      "X travaille Y WHERE U login 'admin', U login N")
+        rset = self.qexecute('Any X, Y WHERE X nom "admin", Y nom "toto", X travaille Y')
         self.assert_(rset.rows)
         self.assertEqual(rset.description, [('Personne', 'Societe',)])
 
     def test_insert_7_2(self):
-        self.execute("INSERT Personne X, Societe Y: X nom N, Y nom 'toto', X travaille Y WHERE U login N")
-        rset = self.execute('Any X, Y WHERE Y nom "toto", X travaille Y')
+        self.qexecute("INSERT Personne X, Societe Y: X nom N, Y nom 'toto', "
+                      "X travaille Y WHERE U login N")
+        rset = self.qexecute('Any X, Y WHERE Y nom "toto", X travaille Y')
         self.assertEqual(len(rset), 2)
         self.assertEqual(rset.description, [('Personne', 'Societe',),
                                              ('Personne', 'Societe',)])
 
     def test_insert_8(self):
-        self.execute("INSERT Societe Y, Personne X: Y nom N, X nom 'toto', X travaille Y WHERE U login 'admin', U login N")
-        rset = self.execute('Any X, Y WHERE X nom "toto", Y nom "admin", X travaille Y')
+        self.qexecute("INSERT Societe Y, Personne X: Y nom N, X nom 'toto', X travaille Y "
+                      "WHERE U login 'admin', U login N")
+        rset = self.qexecute('Any X, Y WHERE X nom "toto", Y nom "admin", X travaille Y')
         self.assert_(rset.rows)
         self.assertEqual(rset.description, [('Personne', 'Societe',)])
 
     def test_insert_9(self):
-        self.execute("INSERT Societe X: X nom  'Lo'")
-        self.execute("INSERT Societe X: X nom  'Gi'")
-        self.execute("INSERT SubDivision X: X nom  'Lab'")
-        rset = self.execute("INSERT Personne X: X nom N, X travaille Y, X travaille_subdivision Z WHERE Y is Societe, Z is SubDivision, Y nom N")
+        self.qexecute("INSERT Societe X: X nom  'Lo'")
+        self.qexecute("INSERT Societe X: X nom  'Gi'")
+        self.qexecute("INSERT SubDivision X: X nom  'Lab'")
+        rset = self.qexecute("INSERT Personne X: X nom N, X travaille Y, X travaille_subdivision Z "
+                             "WHERE Y is Societe, Z is SubDivision, Y nom N")
         self.assertEqual(len(rset), 2)
         self.assertEqual(rset.description, [('Personne',), ('Personne',)])
         # self.assertSetEqual(set(x.nom for x in rset.entities()),
@@ -1075,21 +1122,21 @@
 
     def test_insert_query_error(self):
         self.assertRaises(Exception,
-                          self.execute,
+                          self.qexecute,
                           "INSERT Personne X: X nom 'toto', X is Personne")
         self.assertRaises(Exception,
-                          self.execute,
+                          self.qexecute,
                           "INSERT Personne X: X nom 'toto', X is_instance_of Personne")
         self.assertRaises(QueryError,
-                          self.execute,
+                          self.qexecute,
                           "INSERT Personne X: X nom 'toto', X has_text 'tutu'")
 
         self.assertRaises(QueryError,
-                          self.execute,
+                          self.qexecute,
                           "INSERT CWUser X: X login 'toto', X eid %s" % cnx.user(self.session).eid)
 
     def test_insertion_description_with_where(self):
-        rset = self.execute('INSERT CWUser E, EmailAddress EM: E login "X", E upassword "X", '
+        rset = self.qexecute('INSERT CWUser E, EmailAddress EM: E login "X", E upassword "X", '
                             'E primary_email EM, EM address "X", E in_group G '
                             'WHERE G name "managers"')
         self.assertEqual(list(rset.description[0]), ['CWUser', 'EmailAddress'])
@@ -1097,54 +1144,58 @@
     # deletion queries tests ##################################################
 
     def test_delete_1(self):
-        self.execute("INSERT Personne Y: Y nom 'toto'")
-        rset = self.execute('Personne X WHERE X nom "toto"')
+        self.qexecute("INSERT Personne Y: Y nom 'toto'")
+        rset = self.qexecute('Personne X WHERE X nom "toto"')
         self.assertEqual(len(rset.rows), 1)
-        drset = self.execute("DELETE Personne Y WHERE Y nom 'toto'")
+        drset = self.qexecute("DELETE Personne Y WHERE Y nom 'toto'")
         self.assertEqual(drset.rows, rset.rows)
-        rset = self.execute('Personne X WHERE X nom "toto"')
+        rset = self.qexecute('Personne X WHERE X nom "toto"')
         self.assertEqual(len(rset.rows), 0)
 
     def test_delete_2(self):
-        rset = self.execute("INSERT Personne X, Personne Y, Societe Z : X nom 'syt', Y nom 'adim', Z nom 'Logilab', X travaille Z, Y travaille Z")
+        rset = self.qexecute("INSERT Personne X, Personne Y, Societe Z : "
+                             "X nom 'syt', Y nom 'adim', Z nom 'Logilab', X travaille Z, Y travaille Z")
         self.assertEqual(len(rset), 1)
         self.assertEqual(len(rset[0]), 3)
         self.assertEqual(rset.description[0], ('Personne', 'Personne', 'Societe'))
-        self.assertEqual(self.execute('Any N WHERE X nom N, X eid %s'% rset[0][0])[0][0], 'syt')
-        rset = self.execute('Personne X WHERE X travaille Y, Y nom "Logilab"')
+        self.assertEqual(self.qexecute('Any N WHERE X nom N, X eid %s'% rset[0][0])[0][0], 'syt')
+        rset = self.qexecute('Personne X WHERE X travaille Y, Y nom "Logilab"')
         self.assertEqual(len(rset.rows), 2, rset.rows)
-        self.execute("DELETE X travaille Y WHERE X is Personne, Y nom 'Logilabo'")
-        rset = self.execute('Personne X WHERE X travaille Y, Y nom "Logilab"')
+        self.qexecute("DELETE X travaille Y WHERE X is Personne, Y nom 'Logilabo'")
+        rset = self.qexecute('Personne X WHERE X travaille Y, Y nom "Logilab"')
         self.assertEqual(len(rset.rows), 2, rset.rows)
-        self.execute("DELETE X travaille Y WHERE X is Personne, Y nom 'Logilab'")
-        rset = self.execute('Personne X WHERE X travaille Y, Y nom "Logilab"')
+        self.qexecute("DELETE X travaille Y WHERE X is Personne, Y nom 'Logilab'")
+        rset = self.qexecute('Personne X WHERE X travaille Y, Y nom "Logilab"')
         self.assertEqual(len(rset.rows), 0, rset.rows)
 
     def test_delete_3(self):
         s = self.user_groups_session('users')
-        peid, = self.o.execute(s, "INSERT Personne P: P nom 'toto'")[0]
-        seid, = self.o.execute(s, "INSERT Societe S: S nom 'logilab'")[0]
-        self.o.execute(s, "SET P travaille S")
-        rset = self.execute('Personne P WHERE P travaille S')
+        with s.new_cnx() as cnx:
+            with cnx.ensure_cnx_set:
+                peid, = self.o.execute(cnx, "INSERT Personne P: P nom 'toto'")[0]
+                seid, = self.o.execute(cnx, "INSERT Societe S: S nom 'logilab'")[0]
+                self.o.execute(cnx, "SET P travaille S")
+                cnx.commit()
+        rset = self.qexecute('Personne P WHERE P travaille S')
         self.assertEqual(len(rset.rows), 1)
-        self.execute("DELETE X travaille Y WHERE X eid %s, Y eid %s" % (peid, seid))
-        rset = self.execute('Personne P WHERE P travaille S')
+        self.qexecute("DELETE X travaille Y WHERE X eid %s, Y eid %s" % (peid, seid))
+        rset = self.qexecute('Personne P WHERE P travaille S')
         self.assertEqual(len(rset.rows), 0)
 
     def test_delete_symmetric(self):
-        teid1 = self.execute("INSERT Folder T: T name 'toto'")[0][0]
-        teid2 = self.execute("INSERT Folder T: T name 'tutu'")[0][0]
-        self.execute('SET X see_also Y WHERE X eid %s, Y eid %s' % (teid1, teid2))
-        rset = self.execute('Any X,Y WHERE X see_also Y')
+        teid1 = self.qexecute("INSERT Folder T: T name 'toto'")[0][0]
+        teid2 = self.qexecute("INSERT Folder T: T name 'tutu'")[0][0]
+        self.qexecute('SET X see_also Y WHERE X eid %s, Y eid %s' % (teid1, teid2))
+        rset = self.qexecute('Any X,Y WHERE X see_also Y')
         self.assertEqual(len(rset) , 2, rset.rows)
-        self.execute('DELETE X see_also Y WHERE X eid %s, Y eid %s' % (teid1, teid2))
-        rset = self.execute('Any X,Y WHERE X see_also Y')
+        self.qexecute('DELETE X see_also Y WHERE X eid %s, Y eid %s' % (teid1, teid2))
+        rset = self.qexecute('Any X,Y WHERE X see_also Y')
         self.assertEqual(len(rset) , 0)
-        self.execute('SET X see_also Y WHERE X eid %s, Y eid %s' % (teid1, teid2))
-        rset = self.execute('Any X,Y WHERE X see_also Y')
+        self.qexecute('SET X see_also Y WHERE X eid %s, Y eid %s' % (teid1, teid2))
+        rset = self.qexecute('Any X,Y WHERE X see_also Y')
         self.assertEqual(len(rset) , 2)
-        self.execute('DELETE X see_also Y WHERE X eid %s, Y eid %s' % (teid2, teid1))
-        rset = self.execute('Any X,Y WHERE X see_also Y')
+        self.qexecute('DELETE X see_also Y WHERE X eid %s, Y eid %s' % (teid2, teid1))
+        rset = self.qexecute('Any X,Y WHERE X see_also Y')
         self.assertEqual(len(rset) , 0)
 
     def test_nonregr_delete_cache(self):
@@ -1152,204 +1203,221 @@
         (using cachekey on sql generation returned always the same query for an eid,
         whatever the relation)
         """
-        aeid, = self.execute('INSERT EmailAddress X: X address "toto@logilab.fr", X alias "hop"')[0]
+        aeid, = self.qexecute('INSERT EmailAddress X: X address "toto@logilab.fr", X alias "hop"')[0]
         # XXX would be nice if the rql below was enough...
         #'INSERT Email X: X messageid "<1234>", X subject "test", X sender Y, X recipients Y'
-        eeid, = self.execute('INSERT Email X: X messageid "<1234>", X subject "test", X sender Y, X recipients Y WHERE Y is EmailAddress')[0]
-        self.execute("DELETE Email X")
-        sqlc = self.session.cnxset.cu
-        sqlc.execute('SELECT * FROM recipients_relation')
-        self.assertEqual(len(sqlc.fetchall()), 0)
-        sqlc.execute('SELECT * FROM owned_by_relation WHERE eid_from=%s'%eeid)
-        self.assertEqual(len(sqlc.fetchall()), 0)
+        eeid, = self.qexecute('INSERT Email X: X messageid "<1234>", X subject "test", '
+                              'X sender Y, X recipients Y WHERE Y is EmailAddress')[0]
+        self.qexecute("DELETE Email X")
+        with self.session.new_cnx() as cnx:
+            with cnx.ensure_cnx_set:
+                sqlc = cnx.cnxset.cu
+                sqlc.execute('SELECT * FROM recipients_relation')
+                self.assertEqual(len(sqlc.fetchall()), 0)
+                sqlc.execute('SELECT * FROM owned_by_relation WHERE eid_from=%s'%eeid)
+                self.assertEqual(len(sqlc.fetchall()), 0)
 
     def test_nonregr_delete_cache2(self):
-        eid = self.execute("INSERT Folder T: T name 'toto'")[0][0]
-        self.commit()
+        eid = self.qexecute("INSERT Folder T: T name 'toto'")[0][0]
         # fill the cache
-        self.execute("Any X WHERE X eid %(x)s", {'x': eid})
-        self.execute("Any X WHERE X eid %s" % eid)
-        self.execute("Folder X WHERE X eid %(x)s", {'x': eid})
-        self.execute("Folder X WHERE X eid %s" % eid)
-        self.execute("DELETE Folder T WHERE T eid %s" % eid)
-        self.commit()
-        rset = self.execute("Any X WHERE X eid %(x)s", {'x': eid})
+        self.qexecute("Any X WHERE X eid %(x)s", {'x': eid})
+        self.qexecute("Any X WHERE X eid %s" % eid)
+        self.qexecute("Folder X WHERE X eid %(x)s", {'x': eid})
+        self.qexecute("Folder X WHERE X eid %s" % eid)
+        self.qexecute("DELETE Folder T WHERE T eid %s" % eid)
+        rset = self.qexecute("Any X WHERE X eid %(x)s", {'x': eid})
         self.assertEqual(rset.rows, [])
-        rset = self.execute("Any X WHERE X eid %s" % eid)
+        rset = self.qexecute("Any X WHERE X eid %s" % eid)
         self.assertEqual(rset.rows, [])
-        rset = self.execute("Folder X WHERE X eid %(x)s", {'x': eid})
+        rset = self.qexecute("Folder X WHERE X eid %(x)s", {'x': eid})
         self.assertEqual(rset.rows, [])
-        rset = self.execute("Folder X WHERE X eid %s" %eid)
+        rset = self.qexecute("Folder X WHERE X eid %s" %eid)
         self.assertEqual(rset.rows, [])
 
     # update queries tests ####################################################
 
     def test_update_1(self):
-        peid = self.execute("INSERT Personne Y: Y nom 'toto'")[0][0]
-        rset = self.execute('Personne X WHERE X nom "toto"')
+        peid = self.qexecute("INSERT Personne Y: Y nom 'toto'")[0][0]
+        rset = self.qexecute('Personne X WHERE X nom "toto"')
         self.assertEqual(len(rset.rows), 1)
-        rset = self.execute("SET X nom 'tutu', X prenom 'original' WHERE X is Personne, X nom 'toto'")
+        rset = self.qexecute("SET X nom 'tutu', X prenom 'original' WHERE X is Personne, X nom 'toto'")
         self.assertEqual(tuplify(rset.rows), [(peid, 'tutu', 'original')])
-        rset = self.execute('Any Y, Z WHERE X is Personne, X nom Y, X prenom Z')
+        rset = self.qexecute('Any Y, Z WHERE X is Personne, X nom Y, X prenom Z')
         self.assertEqual(tuplify(rset.rows), [('tutu', 'original')])
 
     def test_update_2(self):
-        peid, seid = self.execute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto'")[0]
-        rset = self.execute("SET X travaille Y WHERE X nom 'bidule', Y nom 'toto'")
+        peid, seid = self.qexecute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto'")[0]
+        rset = self.qexecute("SET X travaille Y WHERE X nom 'bidule', Y nom 'toto'")
         self.assertEqual(tuplify(rset.rows), [(peid, seid)])
-        rset = self.execute('Any X, Y WHERE X travaille Y')
+        rset = self.qexecute('Any X, Y WHERE X travaille Y')
         self.assertEqual(len(rset.rows), 1)
 
     def test_update_2bis(self):
-        rset = self.execute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto'")
+        rset = self.qexecute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto'")
         eid1, eid2 = rset[0][0], rset[0][1]
-        self.execute("SET X travaille Y WHERE X eid %(x)s, Y eid %(y)s",
+        self.qexecute("SET X travaille Y WHERE X eid %(x)s, Y eid %(y)s",
                       {'x': str(eid1), 'y': str(eid2)})
-        rset = self.execute('Any X, Y WHERE X travaille Y')
+        rset = self.qexecute('Any X, Y WHERE X travaille Y')
         self.assertEqual(len(rset.rows), 1)
         # test add of an existant relation but with NOT X rel Y protection
-        self.assertFalse(self.execute("SET X travaille Y WHERE X eid %(x)s, Y eid %(y)s,"
+        self.assertFalse(self.qexecute("SET X travaille Y WHERE X eid %(x)s, Y eid %(y)s,"
                                  "NOT X travaille Y",
                                  {'x': str(eid1), 'y': str(eid2)}))
 
     def test_update_2ter(self):
-        rset = self.execute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto'")
+        rset = self.qexecute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto'")
         eid1, eid2 = rset[0][0], rset[0][1]
-        self.execute("SET X travaille Y WHERE X eid %(x)s, Y eid %(y)s",
+        self.qexecute("SET X travaille Y WHERE X eid %(x)s, Y eid %(y)s",
                       {'x': unicode(eid1), 'y': unicode(eid2)})
-        rset = self.execute('Any X, Y WHERE X travaille Y')
+        rset = self.qexecute('Any X, Y WHERE X travaille Y')
         self.assertEqual(len(rset.rows), 1)
 
     def test_update_multiple1(self):
-        peid1 = self.execute("INSERT Personne Y: Y nom 'tutu'")[0][0]
-        peid2 = self.execute("INSERT Personne Y: Y nom 'toto'")[0][0]
-        self.execute("SET X nom 'tutu', Y nom 'toto' WHERE X nom 'toto', Y nom 'tutu'")
-        self.assertEqual(self.execute('Any X WHERE X nom "toto"').rows, [[peid1]])
-        self.assertEqual(self.execute('Any X WHERE X nom "tutu"').rows, [[peid2]])
+        peid1 = self.qexecute("INSERT Personne Y: Y nom 'tutu'")[0][0]
+        peid2 = self.qexecute("INSERT Personne Y: Y nom 'toto'")[0][0]
+        self.qexecute("SET X nom 'tutu', Y nom 'toto' WHERE X nom 'toto', Y nom 'tutu'")
+        self.assertEqual(self.qexecute('Any X WHERE X nom "toto"').rows, [[peid1]])
+        self.assertEqual(self.qexecute('Any X WHERE X nom "tutu"').rows, [[peid2]])
 
     def test_update_multiple2(self):
-        ueid = self.execute("INSERT CWUser X: X login 'bob', X upassword 'toto'")[0][0]
-        peid1 = self.execute("INSERT Personne Y: Y nom 'turlu'")[0][0]
-        peid2 = self.execute("INSERT Personne Y: Y nom 'tutu'")[0][0]
-        self.execute('SET P1 owned_by U, P2 owned_by U '
-                     'WHERE P1 eid %s, P2 eid %s, U eid %s' % (peid1, peid2, ueid))
-        self.assertTrue(self.execute('Any X WHERE X eid %s, X owned_by U, U eid %s'
-                                       % (peid1, ueid)))
-        self.assertTrue(self.execute('Any X WHERE X eid %s, X owned_by U, U eid %s'
-                                       % (peid2, ueid)))
+        with self.session.new_cnx() as cnx:
+            ueid = cnx.execute("INSERT CWUser X: X login 'bob', X upassword 'toto'")[0][0]
+            peid1 = cnx.execute("INSERT Personne Y: Y nom 'turlu'")[0][0]
+            peid2 = cnx.execute("INSERT Personne Y: Y nom 'tutu'")[0][0]
+            cnx.execute('SET P1 owned_by U, P2 owned_by U '
+                        'WHERE P1 eid %s, P2 eid %s, U eid %s' % (peid1, peid2, ueid))
+            self.assertTrue(cnx.execute('Any X WHERE X eid %s, X owned_by U, U eid %s'
+                                          % (peid1, ueid)))
+            self.assertTrue(cnx.execute('Any X WHERE X eid %s, X owned_by U, U eid %s'
+                                          % (peid2, ueid)))
 
     def test_update_math_expr(self):
-        orders = [r[0] for r in self.execute('Any O ORDERBY O WHERE ST name "Personne", X from_entity ST, X ordernum O')]
+        orders = [r[0] for r in self.qexecute('Any O ORDERBY O WHERE ST name "Personne", '
+                                              'X from_entity ST, X ordernum O')]
         for i,v in enumerate(orders):
             if v != orders[0]:
                 splitidx = i
                 break
-        self.execute('SET X ordernum Y+1 WHERE X from_entity SE, SE name "Personne", X ordernum Y, X ordernum >= %(order)s',
+        self.qexecute('SET X ordernum Y+1 WHERE X from_entity SE, SE name "Personne", '
+                      'X ordernum Y, X ordernum >= %(order)s',
                      {'order': orders[splitidx]})
-        orders2 = [r[0] for r in self.execute('Any O ORDERBY O WHERE ST name "Personne", X from_entity ST, X ordernum O')]
+        orders2 = [r[0] for r in self.qexecute('Any O ORDERBY O WHERE ST name "Personne", '
+                                               'X from_entity ST, X ordernum O')]
         orders = orders[:splitidx] + [o+1 for o in orders[splitidx:]]
         self.assertEqual(orders2, orders)
 
     def test_update_string_concat(self):
-        beid = self.execute("INSERT Bookmark Y: Y title 'toto', Y path '/view'")[0][0]
-        self.execute('SET X title XN + %(suffix)s WHERE X is Bookmark, X title XN', {'suffix': u'-moved'})
-        newname = self.execute('Any XN WHERE X eid %(x)s, X title XN', {'x': beid})[0][0]
+        beid = self.qexecute("INSERT Bookmark Y: Y title 'toto', Y path '/view'")[0][0]
+        self.qexecute('SET X title XN + %(suffix)s WHERE X is Bookmark, X title XN',
+                      {'suffix': u'-moved'})
+        newname = self.qexecute('Any XN WHERE X eid %(x)s, X title XN', {'x': beid})[0][0]
         self.assertEqual(newname, 'toto-moved')
 
     def test_update_not_exists(self):
-        rset = self.execute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto'")
+        rset = self.qexecute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto'")
         eid1, eid2 = rset[0][0], rset[0][1]
-        rset = self.execute("SET X travaille Y WHERE X eid %(x)s, Y eid %(y)s, "
+        rset = self.qexecute("SET X travaille Y WHERE X eid %(x)s, Y eid %(y)s, "
                             "NOT EXISTS(Z ecrit_par X)",
                             {'x': unicode(eid1), 'y': unicode(eid2)})
         self.assertEqual(tuplify(rset.rows), [(eid1, eid2)])
 
     def test_update_query_error(self):
-        self.execute("INSERT Personne Y: Y nom 'toto'")
-        self.assertRaises(Exception, self.execute, "SET X nom 'toto', X is Personne")
-        self.assertRaises(QueryError, self.execute, "SET X nom 'toto', X has_text 'tutu' WHERE X is Personne")
-        self.assertRaises(QueryError, self.execute, "SET X login 'tutu', X eid %s" % cnx.user(self.session).eid)
+        self.qexecute("INSERT Personne Y: Y nom 'toto'")
+        self.assertRaises(Exception, self.qexecute, "SET X nom 'toto', X is Personne")
+        self.assertRaises(QueryError, self.qexecute, "SET X nom 'toto', X has_text 'tutu' "
+                          "WHERE X is Personne")
+        self.assertRaises(QueryError,
+                          self.qexecute,
+                          "SET X login 'tutu', X eid %s" % cnx.user(self.session).eid)
 
 
     # HAVING on write queries test #############################################
 
     def test_update_having(self):
-        peid1 = self.execute("INSERT Personne Y: Y nom 'hop', Y tel 1")[0][0]
-        peid2 = self.execute("INSERT Personne Y: Y nom 'hop', Y tel 2")[0][0]
-        rset = self.execute("SET X tel 3 WHERE X tel TEL HAVING TEL&1=1")
+        peid1 = self.qexecute("INSERT Personne Y: Y nom 'hop', Y tel 1")[0][0]
+        peid2 = self.qexecute("INSERT Personne Y: Y nom 'hop', Y tel 2")[0][0]
+        rset = self.qexecute("SET X tel 3 WHERE X tel TEL HAVING TEL&1=1")
         self.assertEqual(tuplify(rset.rows), [(peid1, 3)])
 
     def test_insert_having(self):
         self.skipTest('unsupported yet')
-        self.execute("INSERT Personne Y: Y nom 'hop', Y tel 1")[0][0]
-        self.assertFalse(self.execute("INSERT Personne Y: Y nom 'hop', Y tel 2 WHERE X tel XT HAVING XT&2=2"))
-        self.assertTrue(self.execute("INSERT Personne Y: Y nom 'hop', Y tel 2 WHERE X tel XT HAVING XT&1=1"))
+        self.qexecute("INSERT Personne Y: Y nom 'hop', Y tel 1")[0][0]
+        self.assertFalse(self.qexecute("INSERT Personne Y: Y nom 'hop', Y tel 2 "
+                                       "WHERE X tel XT HAVING XT&2=2"))
+        self.assertTrue(self.qexecute("INSERT Personne Y: Y nom 'hop', Y tel 2 "
+                                      "WHERE X tel XT HAVING XT&1=1"))
 
     def test_delete_having(self):
-        self.execute("INSERT Personne Y: Y nom 'hop', Y tel 1")[0][0]
-        self.assertFalse(self.execute("DELETE Personne Y WHERE X tel XT HAVING XT&2=2"))
-        self.assertTrue(self.execute("DELETE Personne Y WHERE X tel XT HAVING XT&1=1"))
+        self.qexecute("INSERT Personne Y: Y nom 'hop', Y tel 1")[0][0]
+        self.assertFalse(self.qexecute("DELETE Personne Y WHERE X tel XT HAVING XT&2=2"))
+        self.assertTrue(self.qexecute("DELETE Personne Y WHERE X tel XT HAVING XT&1=1"))
 
     # upassword encryption tests #################################################
 
     def test_insert_upassword(self):
-        rset = self.execute("INSERT CWUser X: X login 'bob', X upassword 'toto'")
+        rset = self.qexecute("INSERT CWUser X: X login 'bob', X upassword 'toto', "
+                             "X in_group G WHERE G name 'users'")
         self.assertEqual(len(rset.rows), 1)
         self.assertEqual(rset.description, [('CWUser',)])
         self.assertRaises(Unauthorized,
-                          self.execute, "Any P WHERE X is CWUser, X login 'bob', X upassword P")
-        cursor = self.cnxset.cu
-        cursor.execute("SELECT %supassword from %sCWUser WHERE %slogin='bob'"
-                       % (SQL_PREFIX, SQL_PREFIX, SQL_PREFIX))
-        passwd = str(cursor.fetchone()[0])
-        self.assertEqual(passwd, crypt_password('toto', passwd))
-        rset = self.execute("Any X WHERE X is CWUser, X login 'bob', X upassword %(pwd)s",
+                          self.qexecute, "Any P WHERE X is CWUser, X login 'bob', X upassword P")
+        with self.session.new_cnx() as cnx:
+            with cnx.ensure_cnx_set:
+                cursor = cnx.cnxset.cu
+                cursor.execute("SELECT %supassword from %sCWUser WHERE %slogin='bob'"
+                               % (SQL_PREFIX, SQL_PREFIX, SQL_PREFIX))
+                passwd = str(cursor.fetchone()[0])
+                self.assertEqual(passwd, crypt_password('toto', passwd))
+        rset = self.qexecute("Any X WHERE X is CWUser, X login 'bob', X upassword %(pwd)s",
                             {'pwd': Binary(passwd)})
         self.assertEqual(len(rset.rows), 1)
         self.assertEqual(rset.description, [('CWUser',)])
 
     def test_update_upassword(self):
-        rset = self.execute("INSERT CWUser X: X login 'bob', X upassword %(pwd)s", {'pwd': 'toto'})
-        self.assertEqual(rset.description[0][0], 'CWUser')
-        rset = self.execute("SET X upassword %(pwd)s WHERE X is CWUser, X login 'bob'",
-                            {'pwd': 'tutu'})
-        cursor = self.cnxset.cu
-        cursor.execute("SELECT %supassword from %sCWUser WHERE %slogin='bob'"
-                       % (SQL_PREFIX, SQL_PREFIX, SQL_PREFIX))
-        passwd = str(cursor.fetchone()[0])
-        self.assertEqual(passwd, crypt_password('tutu', passwd))
-        rset = self.execute("Any X WHERE X is CWUser, X login 'bob', X upassword %(pwd)s",
-                            {'pwd': Binary(passwd)})
-        self.assertEqual(len(rset.rows), 1)
-        self.assertEqual(rset.description, [('CWUser',)])
+        with self.session.new_cnx() as cnx:
+            with cnx.ensure_cnx_set:
+                rset = cnx.execute("INSERT CWUser X: X login 'bob', X upassword %(pwd)s",
+                                   {'pwd': 'toto'})
+                self.assertEqual(rset.description[0][0], 'CWUser')
+                rset = cnx.execute("SET X upassword %(pwd)s WHERE X is CWUser, X login 'bob'",
+                                   {'pwd': 'tutu'})
+                cursor = cnx.cnxset.cu
+                cursor.execute("SELECT %supassword from %sCWUser WHERE %slogin='bob'"
+                               % (SQL_PREFIX, SQL_PREFIX, SQL_PREFIX))
+                passwd = str(cursor.fetchone()[0])
+                self.assertEqual(passwd, crypt_password('tutu', passwd))
+                rset = cnx.execute("Any X WHERE X is CWUser, X login 'bob', X upassword %(pwd)s",
+                                   {'pwd': Binary(passwd)})
+                self.assertEqual(len(rset.rows), 1)
+                self.assertEqual(rset.description, [('CWUser',)])
 
     # ZT datetime tests ########################################################
 
     def test_tz_datetime(self):
-        self.execute("INSERT Personne X: X nom 'bob', X tzdatenaiss %(date)s",
+        self.qexecute("INSERT Personne X: X nom 'bob', X tzdatenaiss %(date)s",
                      {'date': datetime(1977, 6, 7, 2, 0, tzinfo=FixedOffset(1))})
-        datenaiss = self.execute("Any XD WHERE X nom 'bob', X tzdatenaiss XD")[0][0]
+        datenaiss = self.qexecute("Any XD WHERE X nom 'bob', X tzdatenaiss XD")[0][0]
         self.assertEqual(datenaiss.tzinfo, None)
         self.assertEqual(datenaiss.utctimetuple()[:5], (1977, 6, 7, 1, 0))
 
     # non regression tests #####################################################
 
     def test_nonregr_1(self):
-        teid = self.execute("INSERT Tag X: X name 'tag'")[0][0]
-        self.execute("SET X tags Y WHERE X name 'tag', Y is State, Y name 'activated'")
-        rset = self.execute('Any X WHERE T tags X')
+        teid = self.qexecute("INSERT Tag X: X name 'tag'")[0][0]
+        self.qexecute("SET X tags Y WHERE X name 'tag', Y is State, Y name 'activated'")
+        rset = self.qexecute('Any X WHERE T tags X')
         self.assertEqual(len(rset.rows), 1, rset.rows)
-        rset = self.execute('Any T WHERE T tags X, X is State')
+        rset = self.qexecute('Any T WHERE T tags X, X is State')
         self.assertEqual(rset.rows, [[teid]])
-        rset = self.execute('Any T WHERE T tags X')
+        rset = self.qexecute('Any T WHERE T tags X')
         self.assertEqual(rset.rows, [[teid]])
 
     def test_nonregr_2(self):
-        teid = self.execute("INSERT Tag X: X name 'tag'")[0][0]
-        geid = self.execute("CWGroup G WHERE G name 'users'")[0][0]
-        self.execute("SET X tags Y WHERE X eid %(t)s, Y eid %(g)s",
+        teid = self.qexecute("INSERT Tag X: X name 'tag'")[0][0]
+        geid = self.qexecute("CWGroup G WHERE G name 'users'")[0][0]
+        self.qexecute("SET X tags Y WHERE X eid %(t)s, Y eid %(g)s",
                        {'g': geid, 't': teid})
-        rset = self.execute('Any X WHERE E eid %(x)s, E tags X',
+        rset = self.qexecute('Any X WHERE E eid %(x)s, E tags X',
                               {'x': teid})
         self.assertEqual(rset.rows, [[geid]])
 
@@ -1357,7 +1425,7 @@
         """bad sql generated on the second query (destination_state is not
         detected as an inlined relation)
         """
-        rset = self.execute('Any S,ES,T WHERE S state_of WF, WF workflow_of ET, ET name "CWUser",'
+        rset = self.qexecute('Any S,ES,T WHERE S state_of WF, WF workflow_of ET, ET name "CWUser",'
                              'ES allowed_transition T, T destination_state S')
         self.assertEqual(len(rset.rows), 2)
 
@@ -1365,26 +1433,28 @@
         # fix variables'type, else we get (nb of entity types with a 'name' attribute)**3
         # union queries and that make for instance a 266Ko sql query which is refused
         # by the server (or client lib)
-        rset = self.execute('Any ER,SE,OE WHERE SE name "Comment", ER name "comments", OE name "Comment",'
+        rset = self.qexecute('Any ER,SE,OE WHERE SE name "Comment", ER name "comments", OE name "Comment",'
                             'ER is CWRType, SE is CWEType, OE is CWEType')
         self.assertEqual(len(rset), 1)
 
     def test_nonregr_5(self):
         # jpl #15505: equivalent queries returning different result sets
-        teid1 = self.execute("INSERT Folder X: X name 'hop'")[0][0]
-        teid2 = self.execute("INSERT Folder X: X name 'hip'")[0][0]
-        neid = self.execute("INSERT Note X: X todo_by U, X filed_under T WHERE U login 'admin', T name 'hop'")[0][0]
-        weid = self.execute("INSERT Affaire X: X concerne N, X filed_under T WHERE N is Note, T name 'hip'")[0][0]
-        rset1 = self.execute('Any N,U WHERE N filed_under T, T eid %s,'
+        teid1 = self.qexecute("INSERT Folder X: X name 'hop'")[0][0]
+        teid2 = self.qexecute("INSERT Folder X: X name 'hip'")[0][0]
+        neid = self.qexecute("INSERT Note X: X todo_by U, X filed_under T "
+                             "WHERE U login 'admin', T name 'hop'")[0][0]
+        weid = self.qexecute("INSERT Affaire X: X concerne N, X filed_under T "
+                             "WHERE N is Note, T name 'hip'")[0][0]
+        rset1 = self.qexecute('Any N,U WHERE N filed_under T, T eid %s,'
                              'N todo_by U, W concerne N,'
                              'W is Affaire, W filed_under A, A eid %s' % (teid1, teid2))
-        rset2 = self.execute('Any N,U WHERE N filed_under T, T eid %s,'
+        rset2 = self.qexecute('Any N,U WHERE N filed_under T, T eid %s,'
                              'N todo_by U, W concerne N,'
                              'W filed_under A, A eid %s' % (teid1, teid2))
-        rset3 = self.execute('Any N,U WHERE N todo_by U, T eid %s,'
+        rset3 = self.qexecute('Any N,U WHERE N todo_by U, T eid %s,'
                              'N filed_under T, W concerne N,'
                              'W is Affaire, W filed_under A, A eid %s' % (teid1, teid2))
-        rset4 = self.execute('Any N,U WHERE N todo_by U, T eid %s,'
+        rset4 = self.qexecute('Any N,U WHERE N todo_by U, T eid %s,'
                              'N filed_under T, W concerne N,'
                              'W filed_under A, A eid %s' % (teid1, teid2))
         self.assertEqual(rset1.rows, rset2.rows)
@@ -1392,19 +1462,19 @@
         self.assertEqual(rset1.rows, rset4.rows)
 
     def test_nonregr_6(self):
-        self.execute('Any N,COUNT(S) GROUPBY N ORDERBY COUNT(N) WHERE S name N, S is State')
+        self.qexecute('Any N,COUNT(S) GROUPBY N ORDERBY COUNT(N) WHERE S name N, S is State')
 
     def test_sqlite_encoding(self):
         """XXX this test was trying to show a bug on use of lower which only
         occurs with non ascii string and misconfigured locale
         """
-        self.execute("INSERT Tag X: X name %(name)s,"
+        self.qexecute("INSERT Tag X: X name %(name)s,"
                        "X modification_date %(modification_date)s,"
                        "X creation_date %(creation_date)s",
                        {'name': u'éname0',
                         'modification_date': '2003/03/12 11:00',
                         'creation_date': '2000/07/03 11:00'})
-        rset = self.execute('Any lower(N) ORDERBY LOWER(N) WHERE X is Tag, X name N,'
+        rset = self.qexecute('Any lower(N) ORDERBY LOWER(N) WHERE X is Tag, X name N,'
                             'X owned_by U, U eid %(x)s',
                             {'x':self.session.user.eid})
         self.assertEqual(rset.rows, [[u'\xe9name0']])
@@ -1415,35 +1485,34 @@
         solutions may be "fusionned" into one by the querier while all solutions
         are needed to build the result's description
         """
-        self.execute("INSERT Personne X: X nom 'bidule'")
-        self.execute("INSERT Societe Y: Y nom 'toto'")
-        beid = self.execute("INSERT Basket B: B name 'mybasket'")[0][0]
-        self.execute("SET X in_basket B WHERE X is Personne")
-        self.execute("SET X in_basket B WHERE X is Societe")
-        rset = self.execute('Any X WHERE X in_basket B, B eid %s' % beid)
+        self.qexecute("INSERT Personne X: X nom 'bidule'")
+        self.qexecute("INSERT Societe Y: Y nom 'toto'")
+        beid = self.qexecute("INSERT Basket B: B name 'mybasket'")[0][0]
+        self.qexecute("SET X in_basket B WHERE X is Personne")
+        self.qexecute("SET X in_basket B WHERE X is Societe")
+        rset = self.qexecute('Any X WHERE X in_basket B, B eid %s' % beid)
         self.assertEqual(len(rset), 2)
         self.assertEqual(rset.description, [('Personne',), ('Societe',)])
 
 
     def test_nonregr_cache_1(self):
-        peid = self.execute("INSERT Personne X: X nom 'bidule'")[0][0]
-        beid = self.execute("INSERT Basket X: X name 'tag'")[0][0]
-        self.execute("SET X in_basket Y WHERE X is Personne, Y eid %(y)s",
+        peid = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0]
+        beid = self.qexecute("INSERT Basket X: X name 'tag'")[0][0]
+        self.qexecute("SET X in_basket Y WHERE X is Personne, Y eid %(y)s",
                        {'y': beid})
-        rset = self.execute("Any X WHERE X in_basket B, B eid %(x)s",
+        rset = self.qexecute("Any X WHERE X in_basket B, B eid %(x)s",
                        {'x': beid})
         self.assertEqual(rset.rows, [[peid]])
-        rset = self.execute("Any X WHERE X in_basket B, B eid %(x)s",
+        rset = self.qexecute("Any X WHERE X in_basket B, B eid %(x)s",
                        {'x': beid})
         self.assertEqual(rset.rows, [[peid]])
 
     def test_nonregr_has_text_cache(self):
-        eid1 = self.execute("INSERT Personne X: X nom 'bidule'")[0][0]
-        eid2 = self.execute("INSERT Personne X: X nom 'tag'")[0][0]
-        self.commit()
-        rset = self.execute("Any X WHERE X has_text %(text)s", {'text': 'bidule'})
+        eid1 = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0]
+        eid2 = self.qexecute("INSERT Personne X: X nom 'tag'")[0][0]
+        rset = self.qexecute("Any X WHERE X has_text %(text)s", {'text': 'bidule'})
         self.assertEqual(rset.rows, [[eid1]])
-        rset = self.execute("Any X WHERE X has_text %(text)s", {'text': 'tag'})
+        rset = self.qexecute("Any X WHERE X has_text %(text)s", {'text': 'tag'})
         self.assertEqual(rset.rows, [[eid2]])
 
     def test_nonregr_sortterm_management(self):
@@ -1454,133 +1523,133 @@
 
         need sqlite including http://www.sqlite.org/cvstrac/tktview?tn=3773 fix
         """
-        self.execute('Any X ORDERBY D DESC WHERE X creation_date D')
+        self.qexecute('Any X ORDERBY D DESC WHERE X creation_date D')
 
     def test_nonregr_extra_joins(self):
         ueid = self.session.user.eid
-        teid1 = self.execute("INSERT Folder X: X name 'folder1'")[0][0]
-        teid2 = self.execute("INSERT Folder X: X name 'folder2'")[0][0]
-        neid1 = self.execute("INSERT Note X: X para 'note1'")[0][0]
-        neid2 = self.execute("INSERT Note X: X para 'note2'")[0][0]
-        self.execute("SET X filed_under Y WHERE X eid %s, Y eid %s"
+        teid1 = self.qexecute("INSERT Folder X: X name 'folder1'")[0][0]
+        teid2 = self.qexecute("INSERT Folder X: X name 'folder2'")[0][0]
+        neid1 = self.qexecute("INSERT Note X: X para 'note1'")[0][0]
+        neid2 = self.qexecute("INSERT Note X: X para 'note2'")[0][0]
+        self.qexecute("SET X filed_under Y WHERE X eid %s, Y eid %s"
                        % (neid1, teid1))
-        self.execute("SET X filed_under Y WHERE X eid %s, Y eid %s"
+        self.qexecute("SET X filed_under Y WHERE X eid %s, Y eid %s"
                        % (neid2, teid2))
-        self.execute("SET X todo_by Y WHERE X is Note, Y eid %s" % ueid)
-        rset = self.execute('Any N WHERE N todo_by U, N is Note, U eid %s, N filed_under T, T eid %s'
+        self.qexecute("SET X todo_by Y WHERE X is Note, Y eid %s" % ueid)
+        rset = self.qexecute('Any N WHERE N todo_by U, N is Note, U eid %s, N filed_under T, T eid %s'
                              % (ueid, teid1))
         self.assertEqual(len(rset), 1)
 
     def test_nonregr_XXX(self):
-        teid = self.execute('Transition S WHERE S name "deactivate"')[0][0]
-        rset = self.execute('Any O WHERE O is State, '
+        teid = self.qexecute('Transition S WHERE S name "deactivate"')[0][0]
+        rset = self.qexecute('Any O WHERE O is State, '
                              'S eid %(x)s, S transition_of ET, O state_of ET', {'x': teid})
         self.assertEqual(len(rset), 2)
-        rset = self.execute('Any O WHERE O is State, NOT S destination_state O, '
+        rset = self.qexecute('Any O WHERE O is State, NOT S destination_state O, '
                              'S eid %(x)s, S transition_of ET, O state_of ET', {'x': teid})
         self.assertEqual(len(rset), 1)
 
 
     def test_nonregr_set_datetime(self):
         # huum, psycopg specific
-        self.execute('SET X creation_date %(date)s WHERE X eid 1', {'date': date.today()})
-
-    def test_nonregr_set_query(self):
-        ueid = self.execute("INSERT CWUser X: X login 'bob', X upassword 'toto'")[0][0]
-        self.execute("SET E in_group G, E firstname %(firstname)s, E surname %(surname)s "
-                      "WHERE E eid %(x)s, G name 'users'",
-                      {'x':ueid, 'firstname': u'jean', 'surname': u'paul'})
+        self.qexecute('SET X creation_date %(date)s WHERE X eid 1', {'date': date.today()})
 
     def test_nonregr_u_owned_by_u(self):
-        ueid = self.execute("INSERT CWUser X: X login 'bob', X upassword 'toto', X in_group G "
+        ueid = self.qexecute("INSERT CWUser X: X login 'bob', X upassword 'toto', X in_group G "
                              "WHERE G name 'users'")[0][0]
-        rset = self.execute("CWUser U")
+        rset = self.qexecute("CWUser U")
         self.assertEqual(len(rset), 3) # bob + admin + anon
-        rset = self.execute("Any U WHERE NOT U owned_by U")
-        self.assertEqual(len(rset), 0) # even admin created at repo initialization time should belong to itself
+        rset = self.qexecute("Any U WHERE NOT U owned_by U")
+        # even admin created at repo initialization time should belong to itself
+        self.assertEqual(len(rset), 0)
 
     def test_nonreg_update_index(self):
         # this is the kind of queries generated by "cubicweb-ctl db-check -ry"
-        self.execute("SET X description D WHERE X is State, X description D")
+        self.qexecute("SET X description D WHERE X is State, X description D")
 
     def test_nonregr_is(self):
-        uteid = self.execute('Any ET WHERE ET name "CWUser"')[0][0]
-        self.execute('Any X, ET WHERE X is ET, ET eid %s' % uteid)
+        uteid = self.qexecute('Any ET WHERE ET name "CWUser"')[0][0]
+        self.qexecute('Any X, ET WHERE X is ET, ET eid %s' % uteid)
 
     def test_nonregr_orderby(self):
-        seid = self.execute('Any X WHERE X name "activated"')[0][0]
-        self.execute('Any X,S, MAX(T) GROUPBY X,S ORDERBY S WHERE X is CWUser, T tags X, S eid IN(%s), X in_state S' % seid)
+        seid = self.qexecute('Any X WHERE X name "activated"')[0][0]
+        self.qexecute('Any X,S, MAX(T) GROUPBY X,S ORDERBY S '
+                      'WHERE X is CWUser, T tags X, S eid IN(%s), X in_state S' % seid)
 
     def test_nonregr_solution_cache(self):
         self.skipTest('XXX should be fixed or documented') # (doesn't occur if cache key is provided.)
-        rset = self.execute('Any X WHERE X is CWUser, X eid %(x)s', {'x':self.ueid})
+        rset = self.qexecute('Any X WHERE X is CWUser, X eid %(x)s', {'x':self.ueid})
         self.assertEqual(len(rset), 1)
-        rset = self.execute('Any X WHERE X is CWUser, X eid %(x)s', {'x':12345})
+        rset = self.qexecute('Any X WHERE X is CWUser, X eid %(x)s', {'x':12345})
         self.assertEqual(len(rset), 0)
 
     def test_nonregr_final_norestr(self):
-        self.assertRaises(BadRQLQuery, self.execute, 'Date X')
+        self.assertRaises(BadRQLQuery, self.qexecute, 'Date X')
 
     def test_nonregr_eid_cmp(self):
-        peid1 = self.execute("INSERT Personne X: X nom 'bidule'")[0][0]
-        peid2 = self.execute("INSERT Personne X: X nom 'bidule'")[0][0]
-        rset = self.execute('Any X,Y WHERE X is Personne, Y is Personne, X nom XD, Y nom XD, X eid Z, Y eid > Z')
+        peid1 = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0]
+        peid2 = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0]
+        rset = self.qexecute('Any X,Y WHERE X is Personne, Y is Personne, '
+                             'X nom XD, Y nom XD, X eid Z, Y eid > Z')
         self.assertEqual(rset.rows, [[peid1, peid2]])
-        rset = self.execute('Any X,Y WHERE X nom XD, Y nom XD, X eid Z, Y eid > Z')
+        rset = self.qexecute('Any X,Y WHERE X nom XD, Y nom XD, X eid Z, Y eid > Z')
         self.assertEqual(rset.rows, [[peid1, peid2]])
 
     def test_nonregr_has_text_ambiguity_1(self):
-        peid = self.execute("INSERT CWUser X: X login 'bidule', X upassword 'bidule', X in_group G WHERE G name 'users'")[0][0]
-        aeid = self.execute("INSERT Affaire X: X ref 'bidule'")[0][0]
-        self.commit()
-        rset = self.execute('Any X WHERE X is CWUser, X has_text "bidule"')
+        peid = self.qexecute("INSERT CWUser X: X login 'bidule', X upassword 'bidule', "
+                             "X in_group G WHERE G name 'users'")[0][0]
+        aeid = self.qexecute("INSERT Affaire X: X ref 'bidule'")[0][0]
+        rset = self.qexecute('Any X WHERE X is CWUser, X has_text "bidule"')
         self.assertEqual(rset.rows, [[peid]])
-        rset = self.execute('Any X WHERE X is CWUser, X has_text "bidule", X in_state S, S name SN')
+        rset = self.qexecute('Any X WHERE X is CWUser, X has_text "bidule", '
+                             'X in_state S, S name SN')
         self.assertEqual(rset.rows, [[peid]])
 
 
     def test_nonregr_sql_cache(self):
         # different SQL generated when 'name' is None or not (IS NULL).
-        self.assertFalse(self.execute('Any X WHERE X is CWEType, X name %(name)s', {'name': None}))
-        self.assertTrue(self.execute('Any X WHERE X is CWEType, X name %(name)s', {'name': 'CWEType'}))
+        self.assertFalse(self.qexecute('Any X WHERE X is CWEType, X name %(name)s',
+                                       {'name': None}))
+        self.assertTrue(self.qexecute('Any X WHERE X is CWEType, X name %(name)s',
+                                      {'name': 'CWEType'}))
 
 
 class NonRegressionTC(CubicWebTC):
 
     def test_has_text_security_cache_bug(self):
-        req = self.request()
-        self.create_user(req, 'user', ('users',))
-        aff1 = req.create_entity('Societe', nom=u'aff1')
-        aff2 = req.create_entity('Societe', nom=u'aff2')
-        self.commit()
-        with self.login('user', password='user'):
-            res = self.execute('Any X WHERE X has_text %(text)s', {'text': 'aff1'})
+        with self.admin_access.repo_cnx() as cnx:
+            self.create_user(cnx, 'user', ('users',))
+            aff1 = cnx.create_entity('Societe', nom=u'aff1')
+            aff2 = cnx.create_entity('Societe', nom=u'aff2')
+            cnx.commit()
+        with self.new_access('user').repo_cnx() as cnx:
+            res = cnx.execute('Any X WHERE X has_text %(text)s', {'text': 'aff1'})
             self.assertEqual(res.rows, [[aff1.eid]])
-            res = self.execute('Any X WHERE X has_text %(text)s', {'text': 'aff2'})
+            res = cnx.execute('Any X WHERE X has_text %(text)s', {'text': 'aff2'})
             self.assertEqual(res.rows, [[aff2.eid]])
 
     def test_set_relations_eid(self):
-        req = self.request()
-        # create 3 email addresses
-        a1 = req.create_entity('EmailAddress', address=u'a1')
-        a2 = req.create_entity('EmailAddress', address=u'a2')
-        a3 = req.create_entity('EmailAddress', address=u'a3')
-        # SET relations using '>=' operator on eids
-        req.execute('SET U use_email A WHERE U login "admin", A eid >= %s' % a2.eid)
-        self.assertEqual(
-            [[a2.eid], [a3.eid]],
-            req.execute('Any A ORDERBY A WHERE U use_email A, U login "admin"').rows)
-        # DELETE
-        req.execute('DELETE U use_email A WHERE U login "admin", A eid > %s' % a2.eid)
-        self.assertEqual(
-            [[a2.eid]],
-            req.execute('Any A ORDERBY A WHERE U use_email A, U login "admin"').rows)
-        req.execute('DELETE U use_email A WHERE U login "admin"')
-        # SET relations using '<' operator on eids
-        req.execute('SET U use_email A WHERE U login "admin", A eid < %s' % a2.eid)
-        self.assertEqual(
-            [[a1.eid]],
-            req.execute('Any A ORDERBY A WHERE U use_email A, U login "admin"').rows)
+        with self.admin_access.repo_cnx() as cnx:
+            # create 3 email addresses
+            a1 = cnx.create_entity('EmailAddress', address=u'a1')
+            a2 = cnx.create_entity('EmailAddress', address=u'a2')
+            a3 = cnx.create_entity('EmailAddress', address=u'a3')
+            # SET relations using '>=' operator on eids
+            cnx.execute('SET U use_email A WHERE U login "admin", A eid >= %s' % a2.eid)
+            self.assertEqual(
+                [[a2.eid], [a3.eid]],
+                cnx.execute('Any A ORDERBY A WHERE U use_email A, U login "admin"').rows)
+            # DELETE
+            cnx.execute('DELETE U use_email A WHERE U login "admin", A eid > %s' % a2.eid)
+            self.assertEqual(
+                [[a2.eid]],
+                cnx.execute('Any A ORDERBY A WHERE U use_email A, U login "admin"').rows)
+            cnx.execute('DELETE U use_email A WHERE U login "admin"')
+            # SET relations using '<' operator on eids
+            cnx.execute('SET U use_email A WHERE U login "admin", A eid < %s' % a2.eid)
+            self.assertEqual(
+                [[a1.eid]],
+                cnx.execute('Any A ORDERBY A WHERE U use_email A, U login "admin"').rows)
 
 if __name__ == '__main__':
     unittest_main()
--- a/server/test/unittest_rqlannotation.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/server/test/unittest_rqlannotation.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,5 +1,5 @@
 # -*- coding: iso-8859-1 -*-
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -21,340 +21,424 @@
 from cubicweb.devtools import TestServerConfiguration, get_test_db_handler
 from cubicweb.devtools.repotest import BaseQuerierTC
 
-
-def setUpModule(*args):
-    handler = get_test_db_handler(TestServerConfiguration(
-        'data2', apphome=SQLGenAnnotatorTC.datadir))
-    handler.build_db_cache()
-    global repo, cnx
-    repo, cnx = handler.get_repo_and_cnx()
-
-def tearDownModule(*args):
-    global repo, cnx
-    del repo, cnx
-
-
 class SQLGenAnnotatorTC(BaseQuerierTC):
 
     def setUp(self):
+        handler = get_test_db_handler(TestServerConfiguration(
+            'data2', apphome=SQLGenAnnotatorTC.datadir))
+        handler.build_db_cache()
+        repo, _cnx = handler.get_repo_and_cnx()
         self.__class__.repo = repo
         super(SQLGenAnnotatorTC, self).setUp()
 
     def get_max_eid(self):
         # no need for cleanup here
         return None
+
     def cleanup(self):
         # no need for cleanup here
         pass
 
     def test_0_1(self):
-        rqlst = self._prepare('Any SEN,RN,OEN WHERE X from_entity SE, SE eid 44, X relation_type R, R eid 139, X to_entity OE, OE eid 42, R name RN, SE name SEN, OE name OEN')
-        self.assertEqual(rqlst.defined_vars['SE']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['OE']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['R']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['SE'].stinfo['attrvar'], None)
-        self.assertEqual(rqlst.defined_vars['OE'].stinfo['attrvar'], None)
-        self.assertEqual(rqlst.defined_vars['R'].stinfo['attrvar'], None)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any SEN,RN,OEN WHERE X from_entity SE, '
+                                  'SE eid 44, X relation_type R, R eid 139, '
+                                  'X to_entity OE, OE eid 42, R name RN, SE name SEN, '
+                                  'OE name OEN')
+            self.assertEqual(rqlst.defined_vars['SE']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['OE']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['R']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['SE'].stinfo['attrvar'], None)
+            self.assertEqual(rqlst.defined_vars['OE'].stinfo['attrvar'], None)
+            self.assertEqual(rqlst.defined_vars['R'].stinfo['attrvar'], None)
 
     def test_0_2(self):
-        rqlst = self._prepare('Any O WHERE NOT S ecrit_par O, S eid 1, S inline1 P, O inline2 P')
-        self.assertEqual(rqlst.defined_vars['P']._q_invariant, True)
-        self.assertEqual(rqlst.defined_vars['O'].stinfo['attrvar'], None)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any O WHERE NOT S ecrit_par O, S eid 1, '
+                                  'S inline1 P, O inline2 P')
+            self.assertEqual(rqlst.defined_vars['P']._q_invariant, True)
+            self.assertEqual(rqlst.defined_vars['O'].stinfo['attrvar'], None)
 
     def test_0_4(self):
-        rqlst = self._prepare('Any A,B,C WHERE A eid 12,A comment B, A ?wf_info_for C')
-        self.assertEqual(rqlst.defined_vars['A']._q_invariant, False)
-        self.assert_(rqlst.defined_vars['B'].stinfo['attrvar'])
-        self.assertEqual(rqlst.defined_vars['C']._q_invariant, False)
-        self.assertEqual(rqlst.solutions, [{'A': 'TrInfo', 'B': 'String', 'C': 'Affaire'},
-                                      {'A': 'TrInfo', 'B': 'String', 'C': 'CWUser'},
-                                      {'A': 'TrInfo', 'B': 'String', 'C': 'Note'}])
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any A,B,C WHERE A eid 12,A comment B, '
+                                  'A ?wf_info_for C')
+            self.assertEqual(rqlst.defined_vars['A']._q_invariant, False)
+            self.assert_(rqlst.defined_vars['B'].stinfo['attrvar'])
+            self.assertEqual(rqlst.defined_vars['C']._q_invariant, False)
+            self.assertEqual(rqlst.solutions, [{'A': 'TrInfo', 'B': 'String', 'C': 'Affaire'},
+                                          {'A': 'TrInfo', 'B': 'String', 'C': 'CWUser'},
+                                          {'A': 'TrInfo', 'B': 'String', 'C': 'Note'}])
 
     def test_0_5(self):
-        rqlst = self._prepare('Any P WHERE N ecrit_par P, N eid 0')
-        self.assertEqual(rqlst.defined_vars['N']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['P']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any P WHERE N ecrit_par P, N eid 0')
+            self.assertEqual(rqlst.defined_vars['N']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['P']._q_invariant, True)
 
     def test_0_6(self):
-        rqlst = self._prepare('Any P WHERE NOT N ecrit_par P, N eid 512')
-        self.assertEqual(rqlst.defined_vars['P']._q_invariant, False)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any P WHERE NOT N ecrit_par P, N eid 512')
+            self.assertEqual(rqlst.defined_vars['P']._q_invariant, False)
 
     def test_0_7(self):
-        rqlst = self._prepare('Personne X,Y where X nom NX, Y nom NX, X eid XE, not Y eid XE')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False)
-        self.assert_(rqlst.defined_vars['XE'].stinfo['attrvar'])
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Personne X,Y where X nom NX, '
+                                  'Y nom NX, X eid XE, not Y eid XE')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False)
+            self.assert_(rqlst.defined_vars['XE'].stinfo['attrvar'])
 
     def test_0_8(self):
-        rqlst = self._prepare('Any P WHERE X eid 0, NOT X connait P')
-        self.assertEqual(rqlst.defined_vars['P']._q_invariant, False)
-        #self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
-        self.assertEqual(len(rqlst.solutions), 1, rqlst.solutions)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any P WHERE X eid 0, NOT X connait P')
+            self.assertEqual(rqlst.defined_vars['P']._q_invariant, False)
+            #self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
+            self.assertEqual(len(rqlst.solutions), 1, rqlst.solutions)
 
     def test_0_10(self):
-        rqlst = self._prepare('Any X WHERE X concerne Y, Y is Note')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
-        self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X WHERE X concerne Y, Y is Note')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
+            self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False)
 
     def test_0_11(self):
-        rqlst = self._prepare('Any X WHERE X todo_by Y, X is Affaire')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X WHERE X todo_by Y, X is Affaire')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True)
 
     def test_0_12(self):
-        rqlst = self._prepare('Personne P WHERE P concerne A, A concerne S, S nom "Logilab"')
-        self.assertEqual(rqlst.defined_vars['P']._q_invariant, True)
-        self.assertEqual(rqlst.defined_vars['A']._q_invariant, True)
-        self.assertEqual(rqlst.defined_vars['S']._q_invariant, False)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Personne P WHERE P concerne A, '
+                                  'A concerne S, S nom "Logilab"')
+            self.assertEqual(rqlst.defined_vars['P']._q_invariant, True)
+            self.assertEqual(rqlst.defined_vars['A']._q_invariant, True)
+            self.assertEqual(rqlst.defined_vars['S']._q_invariant, False)
 
     def test_1_0(self):
-        rqlst = self._prepare('Any X,Y WHERE X created_by Y, X eid 5, NOT Y eid 6')
-        self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X,Y WHERE X created_by Y, '
+                                  'X eid 5, NOT Y eid 6')
+            self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True)
 
     def test_1_1(self):
-        rqlst = self._prepare('Any X,Y WHERE X created_by Y, X eid 5, NOT Y eid IN (6,7)')
-        self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X,Y WHERE X created_by Y, X eid 5, '
+                                  'NOT Y eid IN (6,7)')
+            self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True)
 
     def test_2(self):
-        rqlst = self._prepare('Any X WHERE X identity Y, Y eid 1')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X WHERE X identity Y, Y eid 1')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
 
     def test_7(self):
-        rqlst = self._prepare('Personne X,Y where X nom NX, Y nom NX, X eid XE, not Y eid XE')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Personne X,Y where X nom NX, Y nom NX, '
+                                  'X eid XE, not Y eid XE')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False)
 
     def test_8(self):
-        # DISTINCT Any P WHERE P require_group %(g)s, NOT %(u)s has_group_permission P, P is CWPermission
-        rqlst = self._prepare('DISTINCT Any X WHERE A concerne X, NOT N migrated_from X, '
-                              'X is Note, N eid 1')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
+        with self.session.new_cnx() as cnx:
+            # DISTINCT Any P WHERE P require_group %(g)s,
+            # NOT %(u)s has_group_permission P, P is CWPermission
+            rqlst = self._prepare(cnx, 'DISTINCT Any X WHERE A concerne X, '
+                                  'NOT N migrated_from X, '
+                                  'X is Note, N eid 1')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
 
     def test_diff_scope_identity_deamb(self):
-        rqlst = self._prepare('Any X WHERE X concerne Y, Y is Note, EXISTS(Y identity Z, Z migrated_from N)')
-        self.assertEqual(rqlst.defined_vars['Z']._q_invariant, True)
-        self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X WHERE X concerne Y, Y is Note, '
+                                  'EXISTS(Y identity Z, Z migrated_from N)')
+            self.assertEqual(rqlst.defined_vars['Z']._q_invariant, True)
+            self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True)
 
     def test_optional_inlined(self):
-        rqlst = self._prepare('Any X,S where X from_state S?')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['S']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X,S where X from_state S?')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['S']._q_invariant, True)
 
     def test_optional_inlined_2(self):
-        rqlst = self._prepare('Any N,A WHERE N? inline1 A')
-        self.assertEqual(rqlst.defined_vars['N']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['A']._q_invariant, False)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any N,A WHERE N? inline1 A')
+            self.assertEqual(rqlst.defined_vars['N']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['A']._q_invariant, False)
 
     def test_optional_1(self):
-        rqlst = self._prepare('Any X,S WHERE X travaille S?')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['S']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X,S WHERE X travaille S?')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['S']._q_invariant, True)
 
     def test_greater_eid(self):
-        rqlst = self._prepare('Any X WHERE X eid > 5')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X WHERE X eid > 5')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
 
     def test_greater_eid_typed(self):
-        rqlst = self._prepare('Any X WHERE X eid > 5, X is Note')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X WHERE X eid > 5, X is Note')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
 
     def test_max_eid(self):
-        rqlst = self._prepare('Any MAX(X)')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any MAX(X)')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
 
     def test_max_eid_typed(self):
-        rqlst = self._prepare('Any MAX(X) WHERE X is Note')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any MAX(X) WHERE X is Note')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
 
     def test_all_entities(self):
-        rqlst = self._prepare('Any X')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
 
     def test_all_typed_entity(self):
-        rqlst = self._prepare('Any X WHERE X is Note')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X WHERE X is Note')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
 
     def test_has_text_1(self):
-        rqlst = self._prepare('Any X WHERE X has_text "toto tata"')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
-        self.assertEqual(rqlst.defined_vars['X'].stinfo['principal'].r_type, 'has_text')
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X WHERE X has_text "toto tata"')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
+            self.assertEqual(rqlst.defined_vars['X'].stinfo['principal'].r_type,
+                             'has_text')
 
     def test_has_text_2(self):
-        rqlst = self._prepare('Any X WHERE X is Personne, X has_text "coucou"')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
-        self.assertEqual(rqlst.defined_vars['X'].stinfo['principal'].r_type, 'has_text')
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X WHERE X is Personne, '
+                                  'X has_text "coucou"')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
+            self.assertEqual(rqlst.defined_vars['X'].stinfo['principal'].r_type,
+                             'has_text')
 
     def test_not_relation_1(self):
-        # P can't be invariant since deambiguification caused by "NOT X require_permission P"
-        # is not considered by generated sql (NOT EXISTS(...))
-        rqlst = self._prepare('Any P,G WHERE P require_group G, NOT X require_permission P')
-        self.assertEqual(rqlst.defined_vars['P']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['G']._q_invariant, True)
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            # P can't be invariant since deambiguification caused by "NOT X require_permission P"
+            # is not considered by generated sql (NOT EXISTS(...))
+            rqlst = self._prepare(cnx, 'Any P,G WHERE P require_group G, '
+                                  'NOT X require_permission P')
+            self.assertEqual(rqlst.defined_vars['P']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['G']._q_invariant, True)
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
 
     def test_not_relation_2(self):
-        rqlst = self._prepare('TrInfo X WHERE X eid 2, NOT X from_state Y, Y is State')
-        self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True)
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'TrInfo X WHERE X eid 2, '
+                                  'NOT X from_state Y, Y is State')
+            self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True)
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
 
     def test_not_relation_3(self):
-        rqlst = self._prepare('Any X, Y WHERE X eid 1, Y eid in (2, 3)')
-        self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X, Y WHERE X eid 1, Y eid in (2, 3)')
+            self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False)
 
     def test_not_relation_4_1(self):
-        rqlst = self._prepare('Note X WHERE NOT Y evaluee X')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Note X WHERE NOT Y evaluee X')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True)
 
     def test_not_relation_4_2(self):
-        rqlst = self._prepare('Any X WHERE NOT Y evaluee X')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X WHERE NOT Y evaluee X')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True)
 
     def test_not_relation_4_3(self):
-        rqlst = self._prepare('Any Y WHERE NOT Y evaluee X')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
-        self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any Y WHERE NOT Y evaluee X')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
+            self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False)
 
     def test_not_relation_4_4(self):
-        rqlst = self._prepare('Any X WHERE NOT Y evaluee X, Y is CWUser')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X WHERE NOT Y evaluee X, Y is CWUser')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False)
 
     def test_not_relation_4_5(self):
-        rqlst = self._prepare('Any X WHERE NOT Y evaluee X, Y eid %s, X is Note' % self.ueid)
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
-        self.assertEqual(rqlst.solutions, [{'X': 'Note'}])
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X WHERE NOT Y evaluee X, '
+                                  'Y eid %s, X is Note' % self.ueid)
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
+            self.assertEqual(rqlst.solutions, [{'X': 'Note'}])
 
     def test_not_relation_5_1(self):
-        rqlst = self._prepare('Any X,Y WHERE X name "CWGroup", Y eid IN(1, 2, 3), NOT X read_permission Y')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X,Y WHERE X name "CWGroup", '
+                                  'Y eid IN(1, 2, 3), NOT X read_permission Y')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False)
 
     def test_not_relation_5_2(self):
-        rqlst = self._prepare('DISTINCT Any X,Y WHERE X name "CWGroup", Y eid IN(1, 2, 3), NOT X read_permission Y')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'DISTINCT Any X,Y WHERE X name "CWGroup", '
+                                  'Y eid IN(1, 2, 3), NOT X read_permission Y')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False)
 
     def test_not_relation_6(self):
-        rqlst = self._prepare('Personne P where NOT P concerne A')
-        self.assertEqual(rqlst.defined_vars['P']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['A']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Personne P where NOT P concerne A')
+            self.assertEqual(rqlst.defined_vars['P']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['A']._q_invariant, True)
 
     def test_not_relation_7(self):
-        rqlst = self._prepare('Any K,V WHERE P is CWProperty, P pkey K, P value V, NOT P for_user U')
-        self.assertEqual(rqlst.defined_vars['P']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['U']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any K,V WHERE P is CWProperty, '
+                                  'P pkey K, P value V, NOT P for_user U')
+            self.assertEqual(rqlst.defined_vars['P']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['U']._q_invariant, True)
 
     def test_exists_1(self):
-        rqlst = self._prepare('Any U WHERE U eid IN (1,2), EXISTS(X owned_by U)')
-        self.assertEqual(rqlst.defined_vars['U']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any U WHERE U eid IN (1,2), EXISTS(X owned_by U)')
+            self.assertEqual(rqlst.defined_vars['U']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
 
     def test_exists_2(self):
-        rqlst = self._prepare('Any U WHERE EXISTS(U eid IN (1,2), X owned_by U)')
-        self.assertEqual(rqlst.defined_vars['U']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any U WHERE EXISTS(U eid IN (1,2), X owned_by U)')
+            self.assertEqual(rqlst.defined_vars['U']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
 
     def test_exists_3(self):
-        rqlst = self._prepare('Any U WHERE EXISTS(X owned_by U, X bookmarked_by U)')
-        self.assertEqual(rqlst.defined_vars['U']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any U WHERE EXISTS(X owned_by U, X bookmarked_by U)')
+            self.assertEqual(rqlst.defined_vars['U']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
 
     def test_exists_4(self):
-        rqlst = self._prepare('Any X,Y WHERE X name "CWGroup", Y eid IN(1, 2, 3), EXISTS(X read_permission Y)')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X,Y WHERE X name "CWGroup", '
+                                  'Y eid IN(1, 2, 3), EXISTS(X read_permission Y)')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False)
 
     def test_exists_5(self):
-        rqlst = self._prepare('DISTINCT Any X,Y WHERE X name "CWGroup", Y eid IN(1, 2, 3), EXISTS(X read_permission Y)')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'DISTINCT Any X,Y WHERE X name "CWGroup", '
+                                  'Y eid IN(1, 2, 3), EXISTS(X read_permission Y)')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True)
 
     def test_not_exists_1(self):
-        rqlst = self._prepare('Any U WHERE NOT EXISTS(X owned_by U, X bookmarked_by U)')
-        self.assertEqual(rqlst.defined_vars['U']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any U WHERE NOT EXISTS(X owned_by U, '
+                                  'X bookmarked_by U)')
+            self.assertEqual(rqlst.defined_vars['U']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
 
     def test_not_exists_2(self):
-        rqlst = self._prepare('Any X,Y WHERE X name "CWGroup", Y eid IN(1, 2, 3), NOT EXISTS(X read_permission Y)')
-        self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X,Y WHERE X name "CWGroup", '
+                                  'Y eid IN(1, 2, 3), NOT EXISTS(X read_permission Y)')
+            self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False)
 
     def test_not_exists_distinct_1(self):
-        rqlst = self._prepare('DISTINCT Any X,Y WHERE X name "CWGroup", Y eid IN(1, 2, 3), NOT EXISTS(X read_permission Y)')
-        self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'DISTINCT Any X,Y WHERE X name "CWGroup", '
+                                  'Y eid IN(1, 2, 3), NOT EXISTS(X read_permission Y)')
+            self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False)
 
     def test_or_1(self):
-        rqlst = self._prepare('Any X WHERE X concerne B OR C concerne X, B eid 12, C eid 13')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X WHERE X concerne B OR '
+                                  'C concerne X, B eid 12, C eid 13')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
 
     def test_or_2(self):
-        rqlst = self._prepare('Any X WHERE X created_by U, X concerne B OR C concerne X, B eid 12, C eid 13')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
-        self.assertEqual(rqlst.defined_vars['U']._q_invariant, True)
-        self.assertEqual(rqlst.defined_vars['X'].stinfo['principal'].r_type, 'created_by')
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X WHERE X created_by U, X concerne B OR '
+                                  'C concerne X, B eid 12, C eid 13')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
+            self.assertEqual(rqlst.defined_vars['U']._q_invariant, True)
+            self.assertEqual(rqlst.defined_vars['X'].stinfo['principal'].r_type, 'created_by')
 
     def test_or_3(self):
-        rqlst = self._prepare('Any N WHERE A evaluee N or EXISTS(N todo_by U)')
-        self.assertEqual(rqlst.defined_vars['N']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['A']._q_invariant, True)
-        self.assertEqual(rqlst.defined_vars['U']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any N WHERE A evaluee N or EXISTS(N todo_by U)')
+            self.assertEqual(rqlst.defined_vars['N']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['A']._q_invariant, True)
+            self.assertEqual(rqlst.defined_vars['U']._q_invariant, True)
 
     def test_or_exists_1(self):
-        # query generated by security rewriting
-        rqlst = self._prepare('DISTINCT Any A,S WHERE A is Affaire, S nom "chouette", S is IN(Division, Societe, SubDivision),'
-                              '(EXISTS(A owned_by D)) '
-                              'OR ((((EXISTS(E concerne C?, C owned_by D, A identity E, C is Note, E is Affaire)) '
-                              'OR (EXISTS(I concerne H?, H owned_by D, H is Societe, A identity I, I is Affaire))) '
-                              'OR (EXISTS(J concerne G?, G owned_by D, G is SubDivision, A identity J, J is Affaire))) '
-                              'OR (EXISTS(K concerne F?, F owned_by D, F is Division, A identity K, K is Affaire)))')
-        self.assertEqual(rqlst.defined_vars['A']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['S']._q_invariant, False)
+        with self.session.new_cnx() as cnx:
+            # query generated by security rewriting
+            rqlst = self._prepare(cnx, 'DISTINCT Any A,S WHERE A is Affaire, S nom "chouette", '
+                                  'S is IN(Division, Societe, SubDivision),'
+                                  '(EXISTS(A owned_by D)) '
+                                  'OR ((((EXISTS(E concerne C?, C owned_by D, A identity E, '
+                                  '              C is Note, E is Affaire)) '
+                                  'OR (EXISTS(I concerne H?, H owned_by D, H is Societe, '
+                                  '           A identity I, I is Affaire))) '
+                                  'OR (EXISTS(J concerne G?, G owned_by D, G is SubDivision, '
+                                  '           A identity J, J is Affaire))) '
+                                  'OR (EXISTS(K concerne F?, F owned_by D, F is Division, '
+                                  '           A identity K, K is Affaire)))')
+            self.assertEqual(rqlst.defined_vars['A']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['S']._q_invariant, False)
 
     def test_or_exists_2(self):
-        rqlst = self._prepare('Any U WHERE EXISTS(U in_group G, G name "managers") OR EXISTS(X owned_by U, X bookmarked_by U)')
-        self.assertEqual(rqlst.defined_vars['U']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['G']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any U WHERE EXISTS(U in_group G, G name "managers") OR '
+                                  'EXISTS(X owned_by U, X bookmarked_by U)')
+            self.assertEqual(rqlst.defined_vars['U']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['G']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, True)
 
     def test_or_exists_3(self):
-        rqlst = self._prepare('Any COUNT(S),CS GROUPBY CS ORDERBY 1 DESC LIMIT 10 '
-                              'WHERE C is Societe, S concerne C, C nom CS, '
-                              '(EXISTS(S owned_by D)) OR (EXISTS(S documented_by N, N title "published"))')
-        self.assertEqual(rqlst.defined_vars['S']._q_invariant, True)
-        rqlst = self._prepare('Any COUNT(S),CS GROUPBY CS ORDERBY 1 DESC LIMIT 10 '
-                              'WHERE S is Affaire, C is Societe, S concerne C, C nom CS, '
-                              '(EXISTS(S owned_by D)) OR (EXISTS(S documented_by N, N title "published"))')
-        self.assertEqual(rqlst.defined_vars['S']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any COUNT(S),CS GROUPBY CS ORDERBY 1 DESC LIMIT 10 '
+                                  'WHERE C is Societe, S concerne C, C nom CS, '
+                                  '(EXISTS(S owned_by D)) OR (EXISTS(S documented_by N, N title "published"))')
+            self.assertEqual(rqlst.defined_vars['S']._q_invariant, True)
+            rqlst = self._prepare(cnx, 'Any COUNT(S),CS GROUPBY CS ORDERBY 1 DESC LIMIT 10 '
+                                  'WHERE S is Affaire, C is Societe, S concerne C, C nom CS, '
+                                  '(EXISTS(S owned_by D)) OR (EXISTS(S documented_by N, N title "published"))')
+            self.assertEqual(rqlst.defined_vars['S']._q_invariant, True)
 
     def test_nonregr_ambiguity(self):
-        rqlst = self._prepare('Note N WHERE N attachment F')
-        # N may be an image as well, not invariant
-        self.assertEqual(rqlst.defined_vars['N']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['F']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Note N WHERE N attachment F')
+            # N may be an image as well, not invariant
+            self.assertEqual(rqlst.defined_vars['N']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['F']._q_invariant, True)
 
     def test_nonregr_ambiguity_2(self):
-        rqlst = self._prepare('Any S,SN WHERE X has_text "tot", X in_state S, S name SN, X is CWUser')
-        # X use has_text but should not be invariant as ambiguous, and has_text
-        # may not be its principal
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['S']._q_invariant, False)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any S,SN WHERE X has_text "tot", X in_state S, S name SN, X is CWUser')
+            # X use has_text but should not be invariant as ambiguous, and has_text
+            # may not be its principal
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['S']._q_invariant, False)
 
     def test_remove_from_deleted_source_1(self):
-        rqlst = self._prepare('Note X WHERE X eid 999998, NOT X cw_source Y')
-        self.assertNotIn('X', rqlst.defined_vars) # simplified
-        self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Note X WHERE X eid 999998, NOT X cw_source Y')
+            self.assertNotIn('X', rqlst.defined_vars) # simplified
+            self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True)
 
     def test_remove_from_deleted_source_2(self):
-        rqlst = self._prepare('Note X WHERE X eid IN (999998, 999999), NOT X cw_source Y')
-        self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
-        self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True)
-
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Note X WHERE X eid IN (999998, 999999), NOT X cw_source Y')
+            self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
+            self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True)
 
     def test_has_text_security_cache_bug(self):
-        rqlst = self._prepare('Any X WHERE X has_text "toto" WITH X BEING '
-                              '(Any C WHERE C is Societe, C nom CS)')
-        self.assertTrue(rqlst.parent.has_text_query)
+        with self.session.new_cnx() as cnx:
+            rqlst = self._prepare(cnx, 'Any X WHERE X has_text "toto" WITH X BEING '
+                                  '(Any C WHERE C is Societe, C nom CS)')
+            self.assertTrue(rqlst.parent.has_text_query)
 
 if __name__ == '__main__':
     from logilab.common.testlib import unittest_main
--- a/sobjects/ldapparser.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/sobjects/ldapparser.py	Fri Jul 18 17:35:25 2014 +0200
@@ -92,9 +92,9 @@
         for groupdict in self.group_source_entities_by_extid.itervalues():
             self._process('CWGroup', groupdict)
 
-    def handle_deletion(self, config, session, myuris):
+    def handle_deletion(self, config, cnx, myuris):
         if config['delete-entities']:
-            super(DataFeedLDAPAdapter, self).handle_deletion(config, session, myuris)
+            super(DataFeedLDAPAdapter, self).handle_deletion(config, cnx, myuris)
             return
         if myuris:
             byetype = {}
@@ -107,9 +107,9 @@
                     continue
                 self.info('deactivate %s %s entities', len(eids), etype)
                 for eid in eids:
-                    wf = session.entity_from_eid(eid).cw_adapt_to('IWorkflowable')
+                    wf = cnx.entity_from_eid(eid).cw_adapt_to('IWorkflowable')
                     wf.fire_transition_if_possible('deactivate')
-        session.commit(free_cnxset=False)
+        cnx.commit()
 
     def update_if_necessary(self, entity, attrs):
         # disable read security to allow password selection
--- a/sobjects/test/unittest_cwxmlparser.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/sobjects/test/unittest_cwxmlparser.py	Fri Jul 18 17:35:25 2014 +0200
@@ -132,13 +132,14 @@
     REMOVE THE DATABASE TEMPLATE else it won't be considered
     """
     test_db_id = 'xmlparser'
+
     @classmethod
-    def pre_setup_database(cls, session, config):
-        myfeed = session.create_entity('CWSource', name=u'myfeed', type=u'datafeed',
+    def pre_setup_database(cls, cnx, config):
+        myfeed = cnx.create_entity('CWSource', name=u'myfeed', type=u'datafeed',
                                    parser=u'cw.entityxml', url=BASEXML)
-        myotherfeed = session.create_entity('CWSource', name=u'myotherfeed', type=u'datafeed',
-                                            parser=u'cw.entityxml', url=OTHERXML)
-        session.commit()
+        myotherfeed = cnx.create_entity('CWSource', name=u'myotherfeed', type=u'datafeed',
+                                        parser=u'cw.entityxml', url=OTHERXML)
+        cnx.commit()
         myfeed.init_mapping([(('CWUser', 'use_email', '*'),
                               u'role=subject\naction=copy'),
                              (('CWUser', 'in_group', '*'),
@@ -153,7 +154,8 @@
                                   (('CWUser', 'in_state', '*'),
                                    u'role=subject\naction=link\nlinkattr=name'),
                                   ])
-        session.create_entity('Tag', name=u'hop')
+        cnx.create_entity('Tag', name=u'hop')
+        cnx.commit()
 
     def test_complete_url(self):
         dfsource = self.repo.sources_by_uri['myfeed']
--- a/test/unittest_entity.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/test/unittest_entity.py	Fri Jul 18 17:35:25 2014 +0200
@@ -23,13 +23,13 @@
 from logilab.common import tempattr
 from logilab.common.decorators import clear_cache
 
-from cubicweb import Binary, Unauthorized
+from cubicweb import Binary
 from cubicweb.devtools.testlib import CubicWebTC
 from cubicweb.mttransforms import HAS_TAL
 from cubicweb.entity import can_use_rest_path
 from cubicweb.entities import fetch_config
 from cubicweb.uilib import soup2xhtml
-from cubicweb.schema import RQLVocabularyConstraint, RRQLExpression
+from cubicweb.schema import  RRQLExpression
 
 class EntityTC(CubicWebTC):
 
@@ -45,16 +45,16 @@
             cls.fetch_attrs, cls.cw_fetch_order = self.backup_dict[cls]
 
     def test_no_prefill_related_cache_bug(self):
-        session = self.session
-        usine = session.create_entity('Usine', lieu=u'Montbeliard')
-        produit = session.create_entity('Produit')
-        # usine was prefilled in glob_add_entity
-        # let's simulate produit creation without prefill
-        produit._cw_related_cache.clear()
-        # use add_relations
-        session.add_relations([('fabrique_par', [(produit.eid, usine.eid)])])
-        self.assertEqual(1, len(usine.reverse_fabrique_par))
-        self.assertEqual(1, len(produit.fabrique_par))
+        with self.admin_access.repo_cnx() as cnx:
+            usine = cnx.create_entity('Usine', lieu=u'Montbeliard')
+            produit = cnx.create_entity('Produit')
+            # usine was prefilled in glob_add_entity
+            # let's simulate produit creation without prefill
+            produit._cw_related_cache.clear()
+            # use add_relations
+            cnx.add_relations([('fabrique_par', [(produit.eid, usine.eid)])])
+            self.assertEqual(1, len(usine.reverse_fabrique_par))
+            self.assertEqual(1, len(produit.fabrique_par))
 
     def test_boolean_value(self):
         with self.admin_access.web_request() as req:
@@ -717,11 +717,11 @@
             self.assertFalse(p1.reverse_evaluee)
 
     def test_complete_relation(self):
-        with self.admin_access.repo_cnx() as session:
-            eid = session.execute(
+        with self.admin_access.repo_cnx() as cnx:
+            eid = cnx.execute(
                 'INSERT TrInfo X: X comment "zou", X wf_info_for U, X from_state S1, X to_state S2 '
                 'WHERE U login "admin", S1 name "activated", S2 name "deactivated"')[0][0]
-            trinfo = session.execute('Any X WHERE X eid %(x)s', {'x': eid}).get_entity(0, 0)
+            trinfo = cnx.execute('Any X WHERE X eid %(x)s', {'x': eid}).get_entity(0, 0)
             trinfo.complete()
             self.assertIsInstance(trinfo.cw_attr_cache['creation_date'], datetime)
             self.assertTrue(trinfo.cw_relation_cached('from_state', 'subject'))
--- a/web/application.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/application.py	Fri Jul 18 17:35:25 2014 +0200
@@ -35,7 +35,7 @@
 from cubicweb import (
     ValidationError, Unauthorized, Forbidden,
     AuthenticationError, NoSelectableObject,
-    BadConnectionId, CW_EVENT_MANAGER)
+    CW_EVENT_MANAGER)
 from cubicweb.repoapi import anonymous_cnx
 from cubicweb.web import LOGGER, component, cors
 from cubicweb.web import (
@@ -88,22 +88,15 @@
         closed, total = 0, 0
         for session in self.current_sessions():
             total += 1
-            try:
-                last_usage_time = session.cnx.check()
-            except AttributeError:
-                last_usage_time = session.mtime
-            except BadConnectionId:
+            last_usage_time = session.mtime
+            no_use_time = (time() - last_usage_time)
+            if session.anonymous_session:
+                if no_use_time >= self.cleanup_anon_session_time:
+                    self.close_session(session)
+                    closed += 1
+            elif session_time is not None and no_use_time >= session_time:
                 self.close_session(session)
                 closed += 1
-            else:
-                no_use_time = (time() - last_usage_time)
-                if session.anonymous_session:
-                    if no_use_time >= self.cleanup_anon_session_time:
-                        self.close_session(session)
-                        closed += 1
-                elif session_time is not None and no_use_time >= session_time:
-                    self.close_session(session)
-                    closed += 1
         return closed, total - closed
 
     def current_sessions(self):
@@ -300,6 +293,21 @@
         """wrapper around _publish to log all queries executed for a given
         accessed path
         """
+        def wrap_set_cnx(func):
+            def wrap_execute(cnx):
+                orig_execute = cnx.execute
+                def execute(rql, kwargs=None, build_descr=True):
+                    tstart, cstart = time(), clock()
+                    rset = orig_execute(rql, kwargs, build_descr=build_descr)
+                    cnx.executed_queries.append((rql, kwargs, time() - tstart, clock() - cstart))
+                    return rset
+                return execute
+            def set_cnx(cnx):
+                func(cnx)
+                cnx.execute = wrap_execute(cnx)
+                cnx.executed_queries = []
+            return set_cnx
+        req.set_cnx = wrap_set_cnx(req.set_cnx)
         try:
             return self.main_handle_request(req, path)
         finally:
--- a/web/data/cubicweb.css	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/data/cubicweb.css	Fri Jul 18 17:35:25 2014 +0200
@@ -200,9 +200,15 @@
   visibility: hidden;
 }
 
-li.invisible {
-  background: none;
-  padding: 0px 0px 1px 1px;
+/* copied verbatim from bootstrap 3.0 */
+.invisible {
+  visibility: hidden;
+}
+
+/* copied verbatim from bootstrap 3.0 */
+.list-unstyled {
+  padding-left: 0;
+  list-style: none;
 }
 
 .caption {
--- a/web/data/cubicweb.edition.js	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/data/cubicweb.edition.js	Fri Jul 18 17:35:25 2014 +0200
@@ -328,7 +328,7 @@
         _postAjaxLoad(dom);
     });
     d.addErrback(function(xxx) {
-        log('xxx =', xxx);
+        cw.log('xxx =', xxx);
     });
 }
 
--- a/web/data/cubicweb.old.css	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/data/cubicweb.old.css	Fri Jul 18 17:35:25 2014 +0200
@@ -219,10 +219,15 @@
   visibility: hidden;
 }
 
-li.invisible {
+/* copied verbatim from bootstrap 3.0 */
+.invisible {
+  visibility: hidden;
+}
+
+/* copied verbatim from bootstrap 3.0 */
+.list-unstyled {
+  padding-left: 0;
   list-style: none;
-  background: none;
-  padding: 0px 0px 1px 1px;
 }
 
 .caption {
--- a/web/request.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/request.py	Fri Jul 18 17:35:25 2014 +0200
@@ -30,7 +30,6 @@
 from datetime import date, datetime
 from urlparse import urlsplit
 import httplib
-from itertools import count
 from warnings import warn
 
 from rql.utils import rqlvar_maker
@@ -82,6 +81,24 @@
     return [v for v in value if v != INTERNAL_FIELD_VALUE]
 
 
+class Counter(object):
+    """A picklable counter object, usable for e.g. page tab index count"""
+    __slots__ = ('value',)
+
+    def __init__(self, initialvalue=0):
+        self.value = initialvalue
+
+    def __call__(self):
+        value = self.value
+        self.value += 1
+        return value
+
+    def __getstate__(self):
+        return {'value': self.value}
+
+    def __setstate__(self, state):
+        self.value = state['value']
+
 
 class _CubicWebRequestBase(RequestSessionBase):
     """abstract HTTP request, should be extended according to the HTTP backend
@@ -201,7 +218,7 @@
     def next_tabindex(self):
         nextfunc = self.get_page_data('nexttabfunc')
         if nextfunc is None:
-            nextfunc = count(1).next
+            nextfunc = Counter(1)
             self.set_page_data('nexttabfunc', nextfunc)
         return nextfunc()
 
--- a/web/test/test_views.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/test/test_views.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -16,8 +16,7 @@
 # You should have received a copy of the GNU Lesser General Public License along
 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
 """automatic tests"""
-from cubicweb.devtools import htmlparser
-from cubicweb.devtools.testlib import CubicWebTC, AutoPopulateTest, AutomaticWebTest
+from cubicweb.devtools.testlib import AutoPopulateTest, AutomaticWebTest
 from cubicweb.view import AnyRsetView
 
 class AutomaticWebTest(AutomaticWebTest):
@@ -28,8 +27,8 @@
         ]
 
     def to_test_etypes(self):
-        # We do not really want to test cube views here. So we can drop testing 
-        # some EntityType. The two Blog types below require the sioc cube that 
+        # We do not really want to test cube views here. So we can drop testing
+        # some EntityType. The two Blog types below require the sioc cube that
         # we do not want to add as a dependency.
         etypes = super(AutomaticWebTest, self).to_test_etypes()
         etypes -= set(('Blog', 'BlogEntry'))
@@ -50,29 +49,34 @@
         """regression test: make sure we can ask a copy of a
         composite entity
         """
-        rset = self.execute('CWUser X WHERE X login "admin"')
-        self.view('copy', rset)
+        with self.admin_access.web_request() as req:
+            rset = req.execute('CWUser X WHERE X login "admin"')
+            self.view('copy', rset, req=req)
 
     def test_sortable_js_added(self):
-        rset = self.execute('CWUser X')
-        # sortable.js should not be included by default
-        self.assertFalse('jquery.tablesorter.js' in self.view('oneline', rset))
-        # but should be included by the tableview
-        rset = self.execute('Any P,F,S LIMIT 1 WHERE P is CWUser, P firstname F, P surname S')
-        self.assertIn('jquery.tablesorter.js', self.view('table', rset).source)
+        with self.admin_access.web_request() as req:
+            rset = req.execute('CWUser X')
+            # sortable.js should not be included by default
+            self.assertFalse('jquery.tablesorter.js' in self.view('oneline', rset, req=req))
+            # but should be included by the tableview
+            rset = req.execute('Any P,F,S LIMIT 1 WHERE P is CWUser, P firstname F, P surname S')
+            self.assertIn('jquery.tablesorter.js', self.view('table', rset, req=req).source)
 
     def test_js_added_only_once(self):
-        self.vreg._loadedmods[__name__] = {}
-        self.vreg.register(SomeView)
-        rset = self.execute('CWUser X')
-        source = self.view('someview', rset).source
-        self.assertEqual(source.count('spam.js'), 1)
+        with self.admin_access.web_request() as req:
+            self.vreg._loadedmods[__name__] = {}
+            self.vreg.register(SomeView)
+            rset = req.execute('CWUser X')
+            source = self.view('someview', rset, req=req).source
+            self.assertEqual(source.count('spam.js'), 1)
 
     def test_unrelateddivs(self):
-        rset = self.execute('Any X WHERE X is CWUser, X login "admin"')
-        group = self.request().create_entity('CWGroup', name=u'R&D')
-        req = self.request(relation='in_group_subject')
-        self.view('unrelateddivs', rset, req)
+        with self.admin_access.client_cnx() as cnx:
+            group = cnx.create_entity('CWGroup', name=u'R&D')
+            cnx.commit()
+        with self.admin_access.web_request(relation='in_group_subject') as req:
+            rset = req.execute('Any X WHERE X is CWUser, X login "admin"')
+            self.view('unrelateddivs', rset, req=req)
 
 
 if __name__ == '__main__':
--- a/web/test/unittest_application.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/test/unittest_application.py	Fri Jul 18 17:35:25 2014 +0200
@@ -18,14 +18,12 @@
 """unit tests for cubicweb.web.application"""
 
 import base64, Cookie
-import sys
 import httplib
-from urllib import unquote
 
 from logilab.common.testlib import TestCase, unittest_main
 from logilab.common.decorators import clear_cache, classproperty
 
-from cubicweb import AuthenticationError, Unauthorized
+from cubicweb import AuthenticationError
 from cubicweb import view
 from cubicweb.devtools.testlib import CubicWebTC, real_error_handling
 from cubicweb.devtools.fake import FakeRequest
@@ -182,7 +180,7 @@
 
     def test_publish_validation_error(self):
         with self.admin_access.web_request() as req:
-            user = self.user()
+            user = self.user(req)
             eid = unicode(user.eid)
             req.form = {
                 'eid':       eid,
--- a/web/test/unittest_breadcrumbs.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/test/unittest_breadcrumbs.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -29,14 +29,19 @@
                             {'f1' : f1.eid, 'f2' : f2.eid})
             req.cnx.commit()
             self.assertEqual(f2.view('breadcrumbs'),
-                             '<a href="http://testing.fr/cubicweb/folder/%s" title="">chi&amp;ld</a>' % f2.eid)
+                             '<a href="http://testing.fr/cubicweb/folder/%s" title="">'
+                             'chi&amp;ld</a>' % f2.eid)
             childrset = f2.as_rset()
             ibc = self.vreg['ctxcomponents'].select('breadcrumbs', req, rset=childrset)
             l = []
             ibc.render(l.append)
-            self.assertEqual(''.join(l),
-                             """<span id="breadcrumbs" class="pathbar">&#160;&gt;&#160;<a href="http://testing.fr/cubicweb/Folder">Folder_plural</a>&#160;&gt;&#160;<a href="http://testing.fr/cubicweb/folder/%s" title="">par&amp;ent</a>&#160;&gt;&#160;
-<a href="http://testing.fr/cubicweb/folder/%s" title="">chi&amp;ld</a></span>""" % (f1.eid, f2.eid))
+            self.assertMultiLineEqual('<span id="breadcrumbs" class="pathbar">&#160;&gt;&#160;'
+                                      '<a href="http://testing.fr/cubicweb/Folder">Folder_plural</a>'
+                                      '&#160;&gt;&#160;<a href="http://testing.fr/cubicweb/folder/%s" '
+                                      'title="">par&amp;ent</a>&#160;&gt;&#160;\n'
+                                      '<a href="http://testing.fr/cubicweb/folder/%s" title="">'
+                                      'chi&amp;ld</a></span>' % (f1.eid, f2.eid),
+                                      ''.join(l))
 
 if __name__ == '__main__':
     from logilab.common.testlib import unittest_main
--- a/web/test/unittest_propertysheet.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/test/unittest_propertysheet.py	Fri Jul 18 17:35:25 2014 +0200
@@ -4,7 +4,7 @@
 
 from logilab.common.testlib import TestCase, unittest_main
 
-from cubicweb.web.propertysheet import *
+from cubicweb.web.propertysheet import PropertySheet, lazystr
 
 DATADIR = join(dirname(__file__), 'data')
 CACHEDIR = join(DATADIR, 'uicache')
--- a/web/test/unittest_reledit.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/test/unittest_reledit.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -34,9 +34,9 @@
 class ClickAndEditFormTC(ReleditMixinTC, CubicWebTC):
 
     def test_default_config(self):
-        reledit = {'title': '''<div id="title-subject-%(eid)s-reledit" onmouseout="jQuery('#title-subject-%(eid)s').addClass('hidden')" onmouseover="jQuery('#title-subject-%(eid)s').removeClass('hidden')" class="releditField"><div id="title-subject-%(eid)s-value" class="editableFieldValue">cubicweb-world-domination</div><div id="title-subject-%(eid)s" class="editableField hidden"><div id="title-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;title&#39;, &#39;subject&#39;, &#39;title-subject-%(eid)s&#39;, false, &#39;&#39;, &#39;edit_rtype&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>''',
-                   'long_desc': '''<div id="long_desc-subject-%(eid)s-reledit" onmouseout="jQuery('#long_desc-subject-%(eid)s').addClass('hidden')" onmouseover="jQuery('#long_desc-subject-%(eid)s').removeClass('hidden')" class="releditField"><div id="long_desc-subject-%(eid)s-value" class="editableFieldValue">&lt;not specified&gt;</div><div id="long_desc-subject-%(eid)s" class="editableField hidden"><div id="long_desc-subject-%(eid)s-add" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;edition&#39;, %(eid)s, &#39;long_desc&#39;, &#39;subject&#39;, &#39;long_desc-subject-%(eid)s&#39;, false, &#39;autolimited&#39;, &#39;add&#39;);" title="click to add a value"><img title="click to add a value" src="http://testing.fr/cubicweb/data/plus.png" alt="click to add a value"/></div></div></div>''',
-                   'manager': '''<div id="manager-subject-%(eid)s-reledit" onmouseout="jQuery('#manager-subject-%(eid)s').addClass('hidden')" onmouseover="jQuery('#manager-subject-%(eid)s').removeClass('hidden')" class="releditField"><div id="manager-subject-%(eid)s-value" class="editableFieldValue">&lt;not specified&gt;</div><div id="manager-subject-%(eid)s" class="editableField hidden"><div id="manager-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;manager&#39;, &#39;subject&#39;, &#39;manager-subject-%(eid)s&#39;, false, &#39;autolimited&#39;, &#39;edit_rtype&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>''',
+        reledit = {'title': '''<div id="title-subject-%(eid)s-reledit" onmouseout="jQuery('#title-subject-%(eid)s').addClass('invisible')" onmouseover="jQuery('#title-subject-%(eid)s').removeClass('invisible')" class="releditField"><div id="title-subject-%(eid)s-value" class="editableFieldValue">cubicweb-world-domination</div><div id="title-subject-%(eid)s" class="editableField invisible"><div id="title-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;title&#39;, &#39;subject&#39;, &#39;title-subject-%(eid)s&#39;, false, &#39;&#39;, &#39;edit_rtype&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>''',
+                   'long_desc': '''<div id="long_desc-subject-%(eid)s-reledit" onmouseout="jQuery('#long_desc-subject-%(eid)s').addClass('invisible')" onmouseover="jQuery('#long_desc-subject-%(eid)s').removeClass('invisible')" class="releditField"><div id="long_desc-subject-%(eid)s-value" class="editableFieldValue">&lt;not specified&gt;</div><div id="long_desc-subject-%(eid)s" class="editableField invisible"><div id="long_desc-subject-%(eid)s-add" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;edition&#39;, %(eid)s, &#39;long_desc&#39;, &#39;subject&#39;, &#39;long_desc-subject-%(eid)s&#39;, false, &#39;autolimited&#39;, &#39;add&#39;);" title="click to add a value"><img title="click to add a value" src="http://testing.fr/cubicweb/data/plus.png" alt="click to add a value"/></div></div></div>''',
+                   'manager': '''<div id="manager-subject-%(eid)s-reledit" onmouseout="jQuery('#manager-subject-%(eid)s').addClass('invisible')" onmouseover="jQuery('#manager-subject-%(eid)s').removeClass('invisible')" class="releditField"><div id="manager-subject-%(eid)s-value" class="editableFieldValue">&lt;not specified&gt;</div><div id="manager-subject-%(eid)s" class="editableField invisible"><div id="manager-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;manager&#39;, &#39;subject&#39;, &#39;manager-subject-%(eid)s&#39;, false, &#39;autolimited&#39;, &#39;edit_rtype&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>''',
                    'composite_card11_2ttypes': """&lt;not specified&gt;""",
                    'concerns': """&lt;not specified&gt;"""}
 
@@ -53,7 +53,7 @@
 
     def test_default_forms(self):
         self.skipTest('Need to check if this test should still run post reledit/doreledit merge')
-        doreledit = {'title': """<div id="title-subject-%(eid)s-reledit" onmouseout="jQuery('#title-subject-%(eid)s').addClass('hidden')" onmouseover="jQuery('#title-subject-%(eid)s').removeClass('hidden')" class="releditField"><div id="title-subject-%(eid)s-value" class="editableFieldValue">cubicweb-world-domination</div><form action="http://testing.fr/cubicweb/validateform?__onsuccess=window.parent.cw.reledit.onSuccess" method="post" enctype="application/x-www-form-urlencoded" id="title-subject-%(eid)s-form" onsubmit="return freezeFormButtons(&#39;title-subject-%(eid)s-form&#39;);" class="releditForm" cubicweb:target="eformframe">
+        doreledit = {'title': """<div id="title-subject-%(eid)s-reledit" onmouseout="jQuery('#title-subject-%(eid)s').addClass('invisible')" onmouseover="jQuery('#title-subject-%(eid)s').removeClass('invisible')" class="releditField"><div id="title-subject-%(eid)s-value" class="editableFieldValue">cubicweb-world-domination</div><form action="http://testing.fr/cubicweb/validateform?__onsuccess=window.parent.cw.reledit.onSuccess" method="post" enctype="application/x-www-form-urlencoded" id="title-subject-%(eid)s-form" onsubmit="return freezeFormButtons(&#39;title-subject-%(eid)s-form&#39;);" class="releditForm" cubicweb:target="eformframe">
 <fieldset>
 <input name="__form_id" type="hidden" value="base" />
 <input name="__errorurl" type="hidden" value="http://testing.fr/cubicweb/view?rql=Blop&amp;vid=blop#title-subject-%(eid)s-form" />
@@ -82,12 +82,12 @@
 <td><button class="validateButton" onclick="cw.reledit.cleanupAfterCancel(&#39;title-subject-%(eid)s&#39;)" tabindex="3" type="button" value="button_cancel"><img alt="CANCEL_ICON" src="http://testing.fr/cubicweb/data/cancel.png" />button_cancel</button></td>
 </tr></table>
 </fieldset>
-</form><div id="title-subject-%(eid)s" class="editableField hidden"><div id="title-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;title&#39;, &#39;subject&#39;, &#39;title-subject-%(eid)s&#39;, false, &#39;&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>""",
+</form><div id="title-subject-%(eid)s" class="editableField invisible"><div id="title-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;title&#39;, &#39;subject&#39;, &#39;title-subject-%(eid)s&#39;, false, &#39;&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>""",
 
-                     'long_desc': """<div id="long_desc-subject-%(eid)s-reledit" onmouseout="jQuery('#long_desc-subject-%(eid)s').addClass('hidden')" onmouseover="jQuery('#long_desc-subject-%(eid)s').removeClass('hidden')" class="releditField"><div id="long_desc-subject-%(eid)s-value" class="editableFieldValue">&lt;not specified&gt;</div><form action="http://testing.fr/cubicweb/validateform?__onsuccess=window.parent.cw.reledit.onSuccess" method="post" enctype="application/x-www-form-urlencoded" id="long_desc-subject-%(eid)s-form" onsubmit="return freezeFormButtons(&#39;long_desc-subject-%(eid)s-form&#39;);" class="releditForm" cubicweb:target="eformframe">
+                     'long_desc': """<div id="long_desc-subject-%(eid)s-reledit" onmouseout="jQuery('#long_desc-subject-%(eid)s').addClass('invisible')" onmouseover="jQuery('#long_desc-subject-%(eid)s').removeClass('invisible')" class="releditField"><div id="long_desc-subject-%(eid)s-value" class="editableFieldValue">&lt;not specified&gt;</div><form action="http://testing.fr/cubicweb/validateform?__onsuccess=window.parent.cw.reledit.onSuccess" method="post" enctype="application/x-www-form-urlencoded" id="long_desc-subject-%(eid)s-form" onsubmit="return freezeFormButtons(&#39;long_desc-subject-%(eid)s-form&#39;);" class="releditForm" cubicweb:target="eformframe">
 <fieldset>
-<input name="__form_id" type="hidden" value="edition" />
-<input name="__errorurl" type="hidden" value="http://testing.fr/cubicweb/view?rql=Blop&amp;vid=blop#long_desc-subject-%(eid)s-form" />
+<input name="__form_id" type="invisible" value="edition" />
+<input name="__errorurl" type="invisible" value="http://testing.fr/cubicweb/view?rql=Blop&amp;vid=blop#long_desc-subject-%(eid)s-form" />
 <input name="__domid" type="hidden" value="long_desc-subject-%(eid)s-form" />
 <input name="__type:A" type="hidden" value="Blog" />
 <input name="eid" type="hidden" value="A" />
@@ -126,9 +126,9 @@
 <td><button class="validateButton" onclick="cw.reledit.cleanupAfterCancel(&#39;long_desc-subject-%(eid)s&#39;)" tabindex="8" type="button" value="button_cancel"><img alt="CANCEL_ICON" src="http://testing.fr/cubicweb/data/cancel.png" />button_cancel</button></td>
 </tr></table>
 </fieldset>
-</form><div id="long_desc-subject-%(eid)s" class="editableField hidden"><div id="long_desc-subject-%(eid)s-add" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;edition&#39;, %(eid)s, &#39;long_desc&#39;, &#39;subject&#39;, &#39;long_desc-subject-%(eid)s&#39;, false, &#39;autolimited&#39;);" title="click to add a value"><img title="click to add a value" src="http://testing.fr/cubicweb/data/plus.png" alt="click to add a value"/></div></div></div>""",
+</form><div id="long_desc-subject-%(eid)s" class="editableField invisible"><div id="long_desc-subject-%(eid)s-add" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;edition&#39;, %(eid)s, &#39;long_desc&#39;, &#39;subject&#39;, &#39;long_desc-subject-%(eid)s&#39;, false, &#39;autolimited&#39;);" title="click to add a value"><img title="click to add a value" src="http://testing.fr/cubicweb/data/plus.png" alt="click to add a value"/></div></div></div>""",
 
-                     'manager': """<div id="manager-subject-%(eid)s-reledit" onmouseout="jQuery('#manager-subject-%(eid)s').addClass('hidden')" onmouseover="jQuery('#manager-subject-%(eid)s').removeClass('hidden')" class="releditField"><div id="manager-subject-%(eid)s-value" class="editableFieldValue">&lt;not specified&gt;</div><form action="http://testing.fr/cubicweb/validateform?__onsuccess=window.parent.cw.reledit.onSuccess" method="post" enctype="application/x-www-form-urlencoded" id="manager-subject-%(eid)s-form" onsubmit="return freezeFormButtons(&#39;manager-subject-%(eid)s-form&#39;);" class="releditForm" cubicweb:target="eformframe">
+                     'manager': """<div id="manager-subject-%(eid)s-reledit" onmouseout="jQuery('#manager-subject-%(eid)s').addClass('invisible')" onmouseover="jQuery('#manager-subject-%(eid)s').removeClass('invisible')" class="releditField"><div id="manager-subject-%(eid)s-value" class="editableFieldValue">&lt;not specified&gt;</div><form action="http://testing.fr/cubicweb/validateform?__onsuccess=window.parent.cw.reledit.onSuccess" method="post" enctype="application/x-www-form-urlencoded" id="manager-subject-%(eid)s-form" onsubmit="return freezeFormButtons(&#39;manager-subject-%(eid)s-form&#39;);" class="releditForm" cubicweb:target="eformframe">
 <fieldset>
 <input name="__form_id" type="hidden" value="base" />
 <input name="__errorurl" type="hidden" value="http://testing.fr/cubicweb/view?rql=Blop&amp;vid=blop#manager-subject-%(eid)s-form" />
@@ -162,7 +162,7 @@
 <td><button class="validateButton" onclick="cw.reledit.cleanupAfterCancel(&#39;manager-subject-%(eid)s&#39;)" tabindex="11" type="button" value="button_cancel"><img alt="CANCEL_ICON" src="http://testing.fr/cubicweb/data/cancel.png" />button_cancel</button></td>
 </tr></table>
 </fieldset>
-</form><div id="manager-subject-%(eid)s" class="editableField hidden"><div id="manager-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;manager&#39;, &#39;subject&#39;, &#39;manager-subject-%(eid)s&#39;, false, &#39;autolimited&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>""",
+</form><div id="manager-subject-%(eid)s" class="editableField invisible"><div id="manager-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;manager&#39;, &#39;subject&#39;, &#39;manager-subject-%(eid)s&#39;, false, &#39;autolimited&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>""",
                      'composite_card11_2ttypes': """&lt;not specified&gt;""",
                      'concerns': """&lt;not specified&gt;"""
             }
@@ -198,11 +198,11 @@
         reledit_ctrl.tag_object_of(('Ticket', 'concerns', 'Project'),
                                    {'edit_target': 'rtype'})
         reledit = {
-            'title': """<div id="title-subject-%(eid)s-reledit" onmouseout="jQuery('#title-subject-%(eid)s').addClass('hidden')" onmouseover="jQuery('#title-subject-%(eid)s').removeClass('hidden')" class="releditField"><div id="title-subject-%(eid)s-value" class="editableFieldValue">cubicweb-world-domination</div><div id="title-subject-%(eid)s" class="editableField hidden"><div id="title-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;title&#39;, &#39;subject&#39;, &#39;title-subject-%(eid)s&#39;, true, &#39;&#39;, &#39;edit_rtype&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>""",
-            'long_desc': """<div id="long_desc-subject-%(eid)s-reledit" onmouseout="jQuery('#long_desc-subject-%(eid)s').addClass('hidden')" onmouseover="jQuery('#long_desc-subject-%(eid)s').removeClass('hidden')" class="releditField"><div id="long_desc-subject-%(eid)s-value" class="editableFieldValue">&lt;long_desc is required&gt;</div><div id="long_desc-subject-%(eid)s" class="editableField hidden"><div id="long_desc-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;long_desc&#39;, &#39;subject&#39;, &#39;long_desc-subject-%(eid)s&#39;, true, &#39;autolimited&#39;, &#39;edit_rtype&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>""",
-            'manager': """<div id="manager-subject-%(eid)s-reledit" onmouseout="jQuery('#manager-subject-%(eid)s').addClass('hidden')" onmouseover="jQuery('#manager-subject-%(eid)s').removeClass('hidden')" class="releditField"><div id="manager-subject-%(eid)s-value" class="editableFieldValue"><a href="http://testing.fr/cubicweb/personne/%(toto)s" title="">Toto</a></div><div id="manager-subject-%(eid)s" class="editableField hidden"><div id="manager-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;edition&#39;, %(eid)s, &#39;manager&#39;, &#39;subject&#39;, &#39;manager-subject-%(eid)s&#39;, false, &#39;autolimited&#39;, &#39;edit_related&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div><div id="manager-subject-%(eid)s-delete" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;deleteconf&#39;, %(eid)s, &#39;manager&#39;, &#39;subject&#39;, &#39;manager-subject-%(eid)s&#39;, false, &#39;autolimited&#39;, &#39;delete&#39;);" title="click to delete this value"><img title="click to delete this value" src="http://testing.fr/cubicweb/data/cancel.png" alt="click to delete this value"/></div></div></div>""",
+            'title': """<div id="title-subject-%(eid)s-reledit" onmouseout="jQuery('#title-subject-%(eid)s').addClass('invisible')" onmouseover="jQuery('#title-subject-%(eid)s').removeClass('invisible')" class="releditField"><div id="title-subject-%(eid)s-value" class="editableFieldValue">cubicweb-world-domination</div><div id="title-subject-%(eid)s" class="editableField invisible"><div id="title-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;title&#39;, &#39;subject&#39;, &#39;title-subject-%(eid)s&#39;, true, &#39;&#39;, &#39;edit_rtype&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>""",
+            'long_desc': """<div id="long_desc-subject-%(eid)s-reledit" onmouseout="jQuery('#long_desc-subject-%(eid)s').addClass('invisible')" onmouseover="jQuery('#long_desc-subject-%(eid)s').removeClass('invisible')" class="releditField"><div id="long_desc-subject-%(eid)s-value" class="editableFieldValue">&lt;long_desc is required&gt;</div><div id="long_desc-subject-%(eid)s" class="editableField invisible"><div id="long_desc-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;long_desc&#39;, &#39;subject&#39;, &#39;long_desc-subject-%(eid)s&#39;, true, &#39;autolimited&#39;, &#39;edit_rtype&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>""",
+            'manager': """<div id="manager-subject-%(eid)s-reledit" onmouseout="jQuery('#manager-subject-%(eid)s').addClass('invisible')" onmouseover="jQuery('#manager-subject-%(eid)s').removeClass('invisible')" class="releditField"><div id="manager-subject-%(eid)s-value" class="editableFieldValue"><a href="http://testing.fr/cubicweb/personne/%(toto)s" title="">Toto</a></div><div id="manager-subject-%(eid)s" class="editableField invisible"><div id="manager-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;edition&#39;, %(eid)s, &#39;manager&#39;, &#39;subject&#39;, &#39;manager-subject-%(eid)s&#39;, false, &#39;autolimited&#39;, &#39;edit_related&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div><div id="manager-subject-%(eid)s-delete" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;deleteconf&#39;, %(eid)s, &#39;manager&#39;, &#39;subject&#39;, &#39;manager-subject-%(eid)s&#39;, false, &#39;autolimited&#39;, &#39;delete&#39;);" title="click to delete this value"><img title="click to delete this value" src="http://testing.fr/cubicweb/data/cancel.png" alt="click to delete this value"/></div></div></div>""",
             'composite_card11_2ttypes': """&lt;not specified&gt;""",
-            'concerns': """<div id="concerns-object-%(eid)s-reledit" onmouseout="jQuery('#concerns-object-%(eid)s').addClass('hidden')" onmouseover="jQuery('#concerns-object-%(eid)s').removeClass('hidden')" class="releditField"><div id="concerns-object-%(eid)s-value" class="editableFieldValue"><a href="http://testing.fr/cubicweb/ticket/%(tick)s" title="">write the code</a></div><div id="concerns-object-%(eid)s" class="editableField hidden"><div id="concerns-object-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;concerns&#39;, &#39;object&#39;, &#39;concerns-object-%(eid)s&#39;, false, &#39;autolimited&#39;, &#39;edit_rtype&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>"""
+            'concerns': """<div id="concerns-object-%(eid)s-reledit" onmouseout="jQuery('#concerns-object-%(eid)s').addClass('invisible')" onmouseover="jQuery('#concerns-object-%(eid)s').removeClass('invisible')" class="releditField"><div id="concerns-object-%(eid)s-value" class="editableFieldValue"><a href="http://testing.fr/cubicweb/ticket/%(tick)s" title="">write the code</a></div><div id="concerns-object-%(eid)s" class="editableField invisible"><div id="concerns-object-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;concerns&#39;, &#39;object&#39;, &#39;concerns-object-%(eid)s&#39;, false, &#39;autolimited&#39;, &#39;edit_rtype&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>"""
             }
         with self.admin_access.web_request() as req:
             proj = req.entity_from_eid(self.proj)
--- a/web/test/unittest_urlpublisher.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/test/unittest_urlpublisher.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -33,106 +33,135 @@
     """test suite for QSPreProcessor"""
 
     def setup_database(self):
-        req = self.request()
-        self.create_user(req, u'ÿsaÿe')
-        b = req.create_entity('BlogEntry', title=u'hell\'o', content=u'blabla')
-        c = req.create_entity('Tag', name=u'yo') # take care: Tag's name normalized to lower case
-        self.execute('SET C tags B WHERE C eid %(c)s, B eid %(b)s', {'c':c.eid, 'b':b.eid})
+        with self.admin_access.repo_cnx() as cnx:
+            self.create_user(cnx, u'ÿsaÿe')
+            b = cnx.create_entity('BlogEntry', title=u'hell\'o', content=u'blabla')
+            # take care: Tag's name normalized to lower case
+            c = cnx.create_entity('Tag', name=u'yo')
+            cnx.execute('SET C tags B WHERE C eid %(c)s, B eid %(b)s',
+                        {'c':c.eid, 'b':b.eid})
+            cnx.commit()
 
-    def process(self, url):
-        req = self.req = self.request()
+    def process(self, req, url):
         return self.app.url_resolver.process(req, url)
 
     def test_raw_path(self):
         """tests raw path resolution'"""
-        self.assertEqual(self.process('view'), ('view', None))
-        self.assertEqual(self.process('edit'), ('edit', None))
-        self.assertRaises(NotFound, self.process, 'whatever')
+        with self.admin_access.web_request() as req:
+            self.assertEqual(self.process(req, 'view'), ('view', None))
+            self.assertEqual(self.process(req, 'edit'), ('edit', None))
+            self.assertRaises(NotFound, self.process, req, 'whatever')
 
     def test_eid_path(self):
         """tests eid path resolution"""
-        self.assertIsInstance(self.process('123')[1], ResultSet)
-        self.assertEqual(len(self.process('123')[1]), 1)
-        self.assertRaises(NotFound, self.process, '123/345')
-        self.assertRaises(NotFound, self.process, 'not_eid')
+        with self.admin_access.web_request() as req:
+            self.assertIsInstance(self.process(req, '123')[1], ResultSet)
+            self.assertEqual(len(self.process(req, '123')[1]), 1)
+            self.assertRaises(NotFound, self.process, req, '123/345')
+            self.assertRaises(NotFound, self.process, req, 'not_eid')
 
     def test_rest_path_etype(self):
         """tests the rest path resolution"""
-        ctrl, rset = self.process('CWEType')
-        self.assertEqual(ctrl, 'view')
-        self.assertEqual(rset.description[0][0], 'CWEType')
-        self.assertEqual(rset.printable_rql(),
-                          "Any X,AA,AB ORDERBY AA WHERE X is_instance_of CWEType, X name AA, X modification_date AB")
+        with self.admin_access.web_request() as req:
+            ctrl, rset = self.process(req, 'CWEType')
+            self.assertEqual(ctrl, 'view')
+            self.assertEqual(rset.description[0][0], 'CWEType')
+            self.assertEqual("Any X,AA,AB ORDERBY AA WHERE X is_instance_of CWEType, "
+                             "X name AA, X modification_date AB",
+                             rset.printable_rql())
 
     def test_rest_path_by_attr(self):
-        ctrl, rset = self.process('CWUser/login/admin')
-        self.assertEqual(ctrl, 'view')
-        self.assertEqual(len(rset), 1)
-        self.assertEqual(rset.description[0][0], 'CWUser')
-        self.assertEqual(rset.printable_rql(), 'Any X,AA,AB,AC,AD WHERE X is_instance_of CWUser, X login AA, X firstname AB, X surname AC, X modification_date AD, X login "admin"')
+        with self.admin_access.web_request() as req:
+            ctrl, rset = self.process(req, 'CWUser/login/admin')
+            self.assertEqual(ctrl, 'view')
+            self.assertEqual(len(rset), 1)
+            self.assertEqual(rset.description[0][0], 'CWUser')
+            self.assertEqual('Any X,AA,AB,AC,AD WHERE X is_instance_of CWUser, '
+                             'X login AA, X firstname AB, X surname AC, '
+                             'X modification_date AD, X login "admin"',
+                             rset.printable_rql())
 
     def test_rest_path_unique_attr(self):
-        ctrl, rset = self.process('cwuser/admin')
-        self.assertEqual(ctrl, 'view')
-        self.assertEqual(len(rset), 1)
-        self.assertEqual(rset.description[0][0], 'CWUser')
-        self.assertEqual(rset.printable_rql(), 'Any X,AA,AB,AC,AD WHERE X is_instance_of CWUser, X login AA, X firstname AB, X surname AC, X modification_date AD, X login "admin"')
+        with self.admin_access.web_request() as req:
+            ctrl, rset = self.process(req, 'cwuser/admin')
+            self.assertEqual(ctrl, 'view')
+            self.assertEqual(len(rset), 1)
+            self.assertEqual(rset.description[0][0], 'CWUser')
+            self.assertEqual('Any X,AA,AB,AC,AD WHERE X is_instance_of CWUser, '
+                             'X login AA, X firstname AB, X surname AC, '
+                             'X modification_date AD, X login "admin"',
+                             rset.printable_rql())
 
     def test_rest_path_eid(self):
-        ctrl, rset = self.process('cwuser/eid/%s' % self.user().eid)
-        self.assertEqual(ctrl, 'view')
-        self.assertEqual(len(rset), 1)
-        self.assertEqual(rset.description[0][0], 'CWUser')
-        self.assertEqual(rset.printable_rql(), 'Any X,AA,AB,AC,AD WHERE X is_instance_of CWUser, X login AA, X firstname AB, X surname AC, X modification_date AD, X eid %s' % rset[0][0])
+        with self.admin_access.web_request() as req:
+            ctrl, rset = self.process(req, 'cwuser/eid/%s' % self.user(req).eid)
+            self.assertEqual(ctrl, 'view')
+            self.assertEqual(len(rset), 1)
+            self.assertEqual(rset.description[0][0], 'CWUser')
+            self.assertEqual('Any X,AA,AB,AC,AD WHERE X is_instance_of CWUser, '
+                             'X login AA, X firstname AB, X surname AC, '
+                             'X modification_date AD, X eid %s' % rset[0][0],
+                             rset.printable_rql())
 
     def test_rest_path_non_ascii_paths(self):
-        ctrl, rset = self.process('CWUser/login/%C3%BFsa%C3%BFe')
-        self.assertEqual(ctrl, 'view')
-        self.assertEqual(len(rset), 1)
-        self.assertEqual(rset.description[0][0], 'CWUser')
-        self.assertEqual(rset.printable_rql(), u'Any X,AA,AB,AC,AD WHERE X is_instance_of CWUser, X login AA, X firstname AB, X surname AC, X modification_date AD, X login "\xffsa\xffe"')
+        with self.admin_access.web_request() as req:
+            ctrl, rset = self.process(req, 'CWUser/login/%C3%BFsa%C3%BFe')
+            self.assertEqual(ctrl, 'view')
+            self.assertEqual(len(rset), 1)
+            self.assertEqual(rset.description[0][0], 'CWUser')
+            self.assertEqual(u'Any X,AA,AB,AC,AD WHERE X is_instance_of CWUser, '
+                             u'X login AA, X firstname AB, X surname AC, '
+                             u'X modification_date AD, X login "\xffsa\xffe"',
+                             rset.printable_rql())
 
     def test_rest_path_quoted_paths(self):
-        ctrl, rset = self.process('BlogEntry/title/hell%27o')
-        self.assertEqual(ctrl, 'view')
-        self.assertEqual(len(rset), 1)
-        self.assertEqual(rset.description[0][0], 'BlogEntry')
-        self.assertEqual(rset.printable_rql(), u'Any X,AA,AB,AC WHERE X is_instance_of BlogEntry, X creation_date AA, X title AB, X modification_date AC, X title "hell\'o"')
+        with self.admin_access.web_request() as req:
+            ctrl, rset = self.process(req, 'BlogEntry/title/hell%27o')
+            self.assertEqual(ctrl, 'view')
+            self.assertEqual(len(rset), 1)
+            self.assertEqual(rset.description[0][0], 'BlogEntry')
+            self.assertEqual(u'Any X,AA,AB,AC WHERE X is_instance_of BlogEntry, '
+                             'X creation_date AA, X title AB, X modification_date AC, '
+                             'X title "hell\'o"',
+                             rset.printable_rql())
 
     def test_rest_path_errors(self):
-        self.assertRaises(NotFound, self.process, 'CWUser/eid/30000')
-        self.assertRaises(NotFound, self.process, 'Workcases')
-        self.assertRaises(NotFound, self.process, 'CWUser/inexistant_attribute/joe')
+        with self.admin_access.web_request() as req:
+            self.assertRaises(NotFound, self.process, req, 'CWUser/eid/30000')
+            self.assertRaises(NotFound, self.process, req, 'Workcases')
+            self.assertRaises(NotFound, self.process, req, 'CWUser/inexistant_attribute/joe')
 
     def test_action_path(self):
         """tests the action path resolution"""
-        self.assertRaises(Redirect, self.process, '1/edit')
-        self.assertRaises(Redirect, self.process, 'Tag/name/yo/edit')
-        self.assertRaises(Redirect, self.process, 'Tag/yo/edit')
-        self.assertRaises(NotFound, self.process, 'view/edit')
-        self.assertRaises(NotFound, self.process, '1/non_action')
-        self.assertRaises(NotFound, self.process, 'CWUser/login/admin/non_action')
+        with self.admin_access.web_request() as req:
+            self.assertRaises(Redirect, self.process, req, '1/edit')
+            self.assertRaises(Redirect, self.process, req, 'Tag/name/yo/edit')
+            self.assertRaises(Redirect, self.process, req, 'Tag/yo/edit')
+            self.assertRaises(NotFound, self.process, req, 'view/edit')
+            self.assertRaises(NotFound, self.process, req, '1/non_action')
+            self.assertRaises(NotFound, self.process, req, 'CWUser/login/admin/non_action')
 
 
     def test_regexp_path(self):
         """tests the regexp path resolution"""
-        ctrl, rset = self.process('add/Task')
-        self.assertEqual(ctrl, 'view')
-        self.assertEqual(rset, None)
-        self.assertEqual(self.req.form, {'etype' : "Task", 'vid' : "creation"})
-        self.assertRaises(NotFound, self.process, 'add/foo/bar')
-
+        with self.admin_access.web_request() as req:
+            ctrl, rset = self.process(req, 'add/Task')
+            self.assertEqual(ctrl, 'view')
+            self.assertEqual(rset, None)
+            self.assertEqual(req.form, {'etype' : "Task", 'vid' : "creation"})
+            self.assertRaises(NotFound, self.process, req, 'add/foo/bar')
 
     def test_nonascii_path(self):
         oldrules = SimpleReqRewriter.rules
         SimpleReqRewriter.rules = [(re.compile('/\w+', re.U), dict(vid='foo')),]
-        try:
-            path = str(FakeRequest().url_quote(u'été'))
-            ctrl, rset = self.process(path)
-            self.assertEqual(rset, None)
-            self.assertEqual(self.req.form, {'vid' : "foo"})
-        finally:
-            SimpleReqRewriter.rules = oldrules
+        with self.admin_access.web_request() as req:
+            try:
+                path = str(FakeRequest().url_quote(u'été'))
+                ctrl, rset = self.process(req, path)
+                self.assertEqual(rset, None)
+                self.assertEqual(req.form, {'vid' : "foo"})
+            finally:
+                SimpleReqRewriter.rules = oldrules
 
 
 if __name__ == '__main__':
--- a/web/test/unittest_urlrewrite.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/test/unittest_urlrewrite.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -21,7 +21,8 @@
 from cubicweb.devtools.testlib import CubicWebTC
 from cubicweb.devtools.fake import FakeRequest
 
-from cubicweb.web.views.urlrewrite import SimpleReqRewriter, SchemaBasedRewriter, rgx, rgx_action
+from cubicweb.web.views.urlrewrite import (SimpleReqRewriter, SchemaBasedRewriter,
+                                           rgx, rgx_action)
 
 
 class UrlRewriteTC(CubicWebTC):
@@ -99,47 +100,51 @@
 
     def test_inheritance(self):
         BaseTransition = self.vreg['etypes'].etype_class('BaseTransition')
-        req = self.request()
-        x = req.create_entity('WorkflowTransition', name=u'test')
-        ctrlid, rset = self.app.url_resolver.process(req, 'basetransition/%s' % x.eid)
-        self.assertEqual(ctrlid, 'view')
-        self.assertEqual(x.eid, rset[0][0])
-        # cw_rest_attr_info is cached but clear_cache doesn't like cached class
-        # method
-        del BaseTransition._cw_rest_attr_info_cache_
-        try:
-            with tempattr(BaseTransition, 'rest_attr', 'name'):
+        with self.admin_access.web_request() as req:
+            x = req.create_entity('WorkflowTransition', name=u'test')
+            ctrlid, rset = self.app.url_resolver.process(req, 'basetransition/%s' % x.eid)
+            self.assertEqual(ctrlid, 'view')
+            self.assertEqual(x.eid, rset[0][0])
+            # cw_rest_attr_info is cached but clear_cache doesn't like cached class
+            # method
+            del BaseTransition._cw_rest_attr_info_cache_
+            try:
+                with tempattr(BaseTransition, 'rest_attr', 'name'):
 
-                ctrlid, rset = self.app.url_resolver.process(req, 'basetransition/%s' % x.name)
-                self.assertEqual(ctrlid, 'view')
-                self.assertEqual(x.eid, rset[0][0])
-        finally:
-            del BaseTransition._cw_rest_attr_info_cache_
+                    ctrlid, rset = self.app.url_resolver.process(req, 'basetransition/%s' % x.name)
+                    self.assertEqual(ctrlid, 'view')
+                    self.assertEqual(x.eid, rset[0][0])
+            finally:
+                del BaseTransition._cw_rest_attr_info_cache_
 
 
 
 class RgxActionRewriteTC(CubicWebTC):
 
     def setup_database(self):
-        req = self.request()
-        self.p1 = self.create_user(req, u'user1')
-        self.p1.cw_set(firstname=u'joe', surname=u'Dalton')
-        self.p2 = self.create_user(req, u'user2')
-        self.p2.cw_set(firstname=u'jack', surname=u'Dalton')
+        with self.admin_access.repo_cnx() as cnx:
+            p1 = self.create_user(cnx, u'user1')
+            p1.cw_set(firstname=u'joe', surname=u'Dalton')
+            p2 = self.create_user(cnx, u'user2')
+            p2.cw_set(firstname=u'jack', surname=u'Dalton')
+            self.p1eid = p1.eid
+            cnx.commit()
 
     def test_rgx_action_with_transforms(self):
         class TestSchemaBasedRewriter(SchemaBasedRewriter):
             rules = [
-                (rgx('/(?P<sn>\w+)/(?P<fn>\w+)'), rgx_action(r'Any X WHERE X surname %(sn)s, X firstname %(fn)s',
-                                                                             argsgroups=('sn', 'fn'),
-                                                                             transforms={'sn' : unicode.capitalize,
-                                                                                         'fn' : unicode.lower,})),
+                (rgx('/(?P<sn>\w+)/(?P<fn>\w+)'),
+                 rgx_action(r'Any X WHERE X surname %(sn)s, '
+                            'X firstname %(fn)s',
+                            argsgroups=('sn', 'fn'),
+                            transforms={'sn' : unicode.capitalize,
+                                        'fn' : unicode.lower,})),
                 ]
-        req = self.request()
-        rewriter = TestSchemaBasedRewriter(req)
-        pmid, rset = rewriter.rewrite(req, u'/DaLToN/JoE')
-        self.assertEqual(len(rset), 1)
-        self.assertEqual(rset[0][0], self.p1.eid)
+        with self.admin_access.web_request() as req:
+            rewriter = TestSchemaBasedRewriter(req)
+            _pmid, rset = rewriter.rewrite(req, u'/DaLToN/JoE')
+            self.assertEqual(len(rset), 1)
+            self.assertEqual(rset[0][0], self.p1eid)
 
     def test_inheritance_precedence(self):
         RQL1 = 'Any C WHERE C is CWEType'
@@ -160,20 +165,20 @@
                 ),
                 ]
 
-        req = self.request()
-        rewriter = Rewriter(req)
-        pmid, rset = rewriter.rewrite(req, '/collector')
-        self.assertEqual(rset.rql, RQL1)
-        self.assertEqual(req.form, {'vid' : "baseindex"})
-        pmid, rset = rewriter.rewrite(req, '/collector/something')
-        self.assertEqual(rset.rql, RQL2)
-        self.assertEqual(req.form, {'vid' : "index"})
-        pmid, rset = rewriter.rewrite(req, '/collector/something/')
-        self.assertEqual(req.form, {'vid' : "index"})
-        self.assertEqual(rset.rql, RQL2)
-        pmid, rset = rewriter.rewrite(req, '/collector/somethingelse/')
-        self.assertEqual(rset.rql, RQL1)
-        self.assertEqual(req.form, {'vid' : "baseindex"})
+        with self.admin_access.web_request() as req:
+            rewriter = Rewriter(req)
+            _pmid, rset = rewriter.rewrite(req, '/collector')
+            self.assertEqual(rset.rql, RQL1)
+            self.assertEqual(req.form, {'vid' : "baseindex"})
+            _pmid, rset = rewriter.rewrite(req, '/collector/something')
+            self.assertEqual(rset.rql, RQL2)
+            self.assertEqual(req.form, {'vid' : "index"})
+            _pmid, rset = rewriter.rewrite(req, '/collector/something/')
+            self.assertEqual(req.form, {'vid' : "index"})
+            self.assertEqual(rset.rql, RQL2)
+            _pmid, rset = rewriter.rewrite(req, '/collector/somethingelse/')
+            self.assertEqual(rset.rql, RQL1)
+            self.assertEqual(req.form, {'vid' : "baseindex"})
 
     def test_inheritance_precedence_same_rgx(self):
         RQL1 = 'Any C WHERE C is CWEType'
@@ -194,20 +199,20 @@
                 ),
                 ]
 
-        req = self.request()
-        rewriter = Rewriter(req)
-        pmid, rset = rewriter.rewrite(req, '/collector')
-        self.assertEqual(rset.rql, RQL2)
-        self.assertEqual(req.form, {'vid' : "index"})
-        pmid, rset = rewriter.rewrite(req, '/collector/something')
-        self.assertEqual(rset.rql, RQL2)
-        self.assertEqual(req.form, {'vid' : "index"})
-        pmid, rset = rewriter.rewrite(req, '/collector/something/')
-        self.assertEqual(req.form, {'vid' : "index"})
-        self.assertEqual(rset.rql, RQL2)
-        pmid, rset = rewriter.rewrite(req, '/collector/somethingelse/')
-        self.assertEqual(rset.rql, RQL2)
-        self.assertEqual(req.form, {'vid' : "index"})
+        with self.admin_access.web_request() as req:
+            rewriter = Rewriter(req)
+            _pmid, rset = rewriter.rewrite(req, '/collector')
+            self.assertEqual(rset.rql, RQL2)
+            self.assertEqual(req.form, {'vid' : "index"})
+            _pmid, rset = rewriter.rewrite(req, '/collector/something')
+            self.assertEqual(rset.rql, RQL2)
+            self.assertEqual(req.form, {'vid' : "index"})
+            _pmid, rset = rewriter.rewrite(req, '/collector/something/')
+            self.assertEqual(req.form, {'vid' : "index"})
+            self.assertEqual(rset.rql, RQL2)
+            _pmid, rset = rewriter.rewrite(req, '/collector/somethingelse/')
+            self.assertEqual(rset.rql, RQL2)
+            self.assertEqual(req.form, {'vid' : "index"})
 
 
 if __name__ == '__main__':
--- a/web/test/unittest_views_basecontrollers.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/test/unittest_views_basecontrollers.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -23,18 +23,16 @@
     from urlparse import parse_qs as url_parse_query
 except ImportError:
     from cgi import parse_qs as url_parse_query
-from logilab.common.testlib import unittest_main, mock_object
+from logilab.common.testlib import unittest_main
 from logilab.common.decorators import monkeypatch
 
 from cubicweb import Binary, NoSelectableObject, ValidationError
-from cubicweb.view import STRICT_DOCTYPE
 from cubicweb.devtools.testlib import CubicWebTC
 from cubicweb.utils import json_dumps
 from cubicweb.uilib import rql_for_eid
-from cubicweb.web import INTERNAL_FIELD_VALUE, Redirect, RequestError, RemoteCallFailed
+from cubicweb.web import Redirect, RemoteCallFailed
 import cubicweb.server.session
 from cubicweb.server.session import Connection as OldConnection
-from cubicweb.entities.authobjs import CWUser
 from cubicweb.web.views.autoform import get_pending_inserts, get_pending_deletes
 from cubicweb.web.views.basecontrollers import JSonController, xhtmlize, jsonize
 from cubicweb.web.views.ajaxcontroller import ajaxfunc, AjaxFunction
@@ -42,15 +40,15 @@
 from cubicweb.server.hook import Hook, Operation
 from cubicweb.predicates import is_instance
 
-u = unicode
-
 def req_form(user):
     return {'eid': [str(user.eid)],
             '_cw_entity_fields:%s' % user.eid: '_cw_generic_field',
             '__type:%s' % user.eid: user.__regid__
             }
 
+
 class EditControllerTC(CubicWebTC):
+
     def setUp(self):
         CubicWebTC.setUp(self)
         self.assertIn('users', self.schema.eschema('CWGroup').get_groups('read'))
@@ -62,611 +60,146 @@
     def test_noparam_edit(self):
         """check behaviour of this controller without any form parameter
         """
-        with self.assertRaises(ValidationError) as cm:
-            self.ctrl_publish(self.request())
-        self.assertEqual(cm.exception.errors, {None: u'no selected entities'})
+        with self.admin_access.web_request() as req:
+            with self.assertRaises(ValidationError) as cm:
+                self.ctrl_publish(req)
+            self.assertEqual(cm.exception.errors, {None: u'no selected entities'})
 
     def test_validation_unique(self):
         """test creation of two linked entities
         """
-        user = self.user()
-        req = self.request()
-        req.form = {'eid': 'X', '__type:X': 'CWUser',
-                    '_cw_entity_fields:X': 'login-subject,upassword-subject',
-                    'login-subject:X': u'admin',
-                    'upassword-subject:X': u'toto',
-                    'upassword-subject-confirm:X': u'toto',
+        with self.admin_access.web_request() as req:
+            req.form = {'eid': 'X', '__type:X': 'CWUser',
+                        '_cw_entity_fields:X': 'login-subject,upassword-subject',
+                        'login-subject:X': u'admin',
+                        'upassword-subject:X': u'toto',
+                        'upassword-subject-confirm:X': u'toto',
                     }
-        with self.assertRaises(ValidationError) as cm:
-            self.ctrl_publish(req)
-        cm.exception.translate(unicode)
-        self.assertEqual(cm.exception.errors, {'login-subject': 'the value "admin" is already used, use another one'})
+            with self.assertRaises(ValidationError) as cm:
+                self.ctrl_publish(req)
+                cm.exception.translate(unicode)
+                self.assertEqual({'login-subject': 'the value "admin" is already used, use another one'},
+                                 cm.exception.errors)
 
     def test_user_editing_itself(self):
         """checking that a manager user can edit itself
         """
-        user = self.user()
-        basegroups = [u(eid) for eid, in self.execute('CWGroup G WHERE X in_group G, X eid %(x)s', {'x': user.eid})]
-        groupeids = [eid for eid, in self.execute('CWGroup G WHERE G name in ("managers", "users")')]
-        groups = [u(eid) for eid in groupeids]
-        req = self.request()
-        eid = u(user.eid)
-        req.form = {
-            'eid': eid, '__type:'+eid: 'CWUser',
-            '_cw_entity_fields:'+eid: 'login-subject,firstname-subject,surname-subject,in_group-subject',
-            'login-subject:'+eid:     u(user.login),
-            'surname-subject:'+eid: u'Th\xe9nault',
-            'firstname-subject:'+eid:   u'Sylvain',
-            'in_group-subject:'+eid:  groups,
-            }
-        path, params = self.expect_redirect_handle_request(req, 'edit')
-        e = self.execute('Any X WHERE X eid %(x)s', {'x': user.eid}).get_entity(0, 0)
-        self.assertEqual(e.firstname, u'Sylvain')
-        self.assertEqual(e.surname, u'Th\xe9nault')
-        self.assertEqual(e.login, user.login)
-        self.assertEqual([g.eid for g in e.in_group], groupeids)
+        with self.admin_access.web_request() as req:
+            user = req.user
+            groupeids = [eid for eid, in req.execute('CWGroup G WHERE G name '
+                                                     'in ("managers", "users")')]
+            groups = [unicode(eid) for eid in groupeids]
+            eid = unicode(user.eid)
+            req.form = {
+                'eid': eid, '__type:'+eid: 'CWUser',
+                '_cw_entity_fields:'+eid: 'login-subject,firstname-subject,surname-subject,in_group-subject',
+                'login-subject:'+eid:     unicode(user.login),
+                'surname-subject:'+eid: u'Th\xe9nault',
+                'firstname-subject:'+eid:   u'Sylvain',
+                'in_group-subject:'+eid:  groups,
+                }
+            self.expect_redirect_handle_request(req, 'edit')
+            e = req.execute('Any X WHERE X eid %(x)s',
+                            {'x': user.eid}).get_entity(0, 0)
+            self.assertEqual(e.firstname, u'Sylvain')
+            self.assertEqual(e.surname, u'Th\xe9nault')
+            self.assertEqual(e.login, user.login)
+            self.assertEqual([g.eid for g in e.in_group], groupeids)
 
     def test_user_can_change_its_password(self):
-        req = self.request()
-        user = self.create_user(req, 'user')
-        cnx = self.login('user')
-        eid = u(user.eid)
-        req.form = {
-            'eid': eid, '__maineid' : eid,
-            '__type:'+eid: 'CWUser',
-            '_cw_entity_fields:'+eid: 'upassword-subject',
-            'upassword-subject:'+eid: 'tournicoton',
-            'upassword-subject-confirm:'+eid: 'tournicoton',
-            }
-        path, params = self.expect_redirect_handle_request(req, 'edit')
-        cnx.commit() # commit to check we don't get late validation error for instance
-        self.assertEqual(path, 'cwuser/user')
-        self.assertNotIn('vid', params)
+        with self.admin_access.repo_cnx() as cnx:
+            self.create_user(cnx, 'user')
+            cnx.commit()
+        with self.new_access('user').web_request() as req:
+            eid = unicode(req.user.eid)
+            req.form = {
+                'eid': eid, '__maineid' : eid,
+                '__type:'+eid: 'CWUser',
+                '_cw_entity_fields:'+eid: 'upassword-subject',
+                'upassword-subject:'+eid: 'tournicoton',
+                'upassword-subject-confirm:'+eid: 'tournicoton',
+                }
+            path, params = self.expect_redirect_handle_request(req, 'edit')
+            req.cnx.commit() # commit to check we don't get late validation error for instance
+            self.assertEqual(path, 'cwuser/user')
+            self.assertNotIn('vid', params)
 
     def test_user_editing_itself_no_relation(self):
         """checking we can edit an entity without specifying some required
         relations (meaning no changes)
         """
-        user = self.user()
-        groupeids = [g.eid for g in user.in_group]
-        req = self.request()
-        eid = u(user.eid)
-        req.form = {
-            'eid':       eid,
-            '__type:'+eid:    'CWUser',
-            '_cw_entity_fields:'+eid: 'login-subject,firstname-subject,surname-subject',
-            'login-subject:'+eid:     u(user.login),
-            'firstname-subject:'+eid: u'Th\xe9nault',
-            'surname-subject:'+eid:   u'Sylvain',
-            }
-        path, params = self.expect_redirect_handle_request(req, 'edit')
-        e = self.execute('Any X WHERE X eid %(x)s', {'x': user.eid}).get_entity(0, 0)
-        self.assertEqual(e.login, user.login)
-        self.assertEqual(e.firstname, u'Th\xe9nault')
-        self.assertEqual(e.surname, u'Sylvain')
-        self.assertEqual([g.eid for g in e.in_group], groupeids)
-        self.assertEqual(e.cw_adapt_to('IWorkflowable').state, 'activated')
+        with self.admin_access.web_request() as req:
+            user = req.user
+            groupeids = [g.eid for g in user.in_group]
+            eid = unicode(user.eid)
+            req.form = {
+                'eid':       eid,
+                '__type:'+eid:    'CWUser',
+                '_cw_entity_fields:'+eid: 'login-subject,firstname-subject,surname-subject',
+                'login-subject:'+eid:     unicode(user.login),
+                'firstname-subject:'+eid: u'Th\xe9nault',
+                'surname-subject:'+eid:   u'Sylvain',
+                }
+            self.expect_redirect_handle_request(req, 'edit')
+            e = req.execute('Any X WHERE X eid %(x)s',
+                            {'x': user.eid}).get_entity(0, 0)
+            self.assertEqual(e.login, user.login)
+            self.assertEqual(e.firstname, u'Th\xe9nault')
+            self.assertEqual(e.surname, u'Sylvain')
+            self.assertEqual([g.eid for g in e.in_group], groupeids)
+            self.assertEqual(e.cw_adapt_to('IWorkflowable').state, 'activated')
 
 
     def test_create_multiple_linked(self):
-        gueid = self.execute('CWGroup G WHERE G name "users"')[0][0]
-        req = self.request()
-        req.form = {'eid': ['X', 'Y'], '__maineid' : 'X',
-
-                    '__type:X': 'CWUser',
-                    '_cw_entity_fields:X': 'login-subject,upassword-subject,surname-subject,in_group-subject',
-                    'login-subject:X': u'adim',
-                    'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto',
-                    'surname-subject:X': u'Di Mascio',
-                    'in_group-subject:X': u(gueid),
+        with self.admin_access.web_request() as req:
+            gueid = req.execute('CWGroup G WHERE G name "users"')[0][0]
+            req.form = {'eid': ['X', 'Y'], '__maineid' : 'X',
+                        '__type:X': 'CWUser',
+                        '_cw_entity_fields:X': 'login-subject,upassword-subject,surname-subject,in_group-subject',
+                        'login-subject:X': u'adim',
+                        'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto',
+                        'surname-subject:X': u'Di Mascio',
+                        'in_group-subject:X': unicode(gueid),
 
-                    '__type:Y': 'EmailAddress',
-                    '_cw_entity_fields:Y': 'address-subject,use_email-object',
-                    'address-subject:Y': u'dima@logilab.fr',
-                    'use_email-object:Y': 'X',
-                    }
-        path, params = self.expect_redirect_handle_request(req, 'edit')
-        # should be redirected on the created person
-        self.assertEqual(path, 'cwuser/adim')
-        e = self.execute('Any P WHERE P surname "Di Mascio"').get_entity(0, 0)
-        self.assertEqual(e.surname, 'Di Mascio')
-        email = e.use_email[0]
-        self.assertEqual(email.address, 'dima@logilab.fr')
+                        '__type:Y': 'EmailAddress',
+                        '_cw_entity_fields:Y': 'address-subject,use_email-object',
+                        'address-subject:Y': u'dima@logilab.fr',
+                        'use_email-object:Y': 'X',
+                        }
+            path, _params = self.expect_redirect_handle_request(req, 'edit')
+            # should be redirected on the created person
+            self.assertEqual(path, 'cwuser/adim')
+            e = req.execute('Any P WHERE P surname "Di Mascio"').get_entity(0, 0)
+            self.assertEqual(e.surname, 'Di Mascio')
+            email = e.use_email[0]
+            self.assertEqual(email.address, 'dima@logilab.fr')
 
     def test_create_mandatory_inlined(self):
-        req = self.request()
-        req.form = {'eid': ['X', 'Y'], '__maineid' : 'X',
+        with self.admin_access.web_request() as req:
+            req.form = {'eid': ['X', 'Y'], '__maineid' : 'X',
 
-                    '__type:X': 'Salesterm',
-                    '_cw_entity_fields:X': '',
+                        '__type:X': 'Salesterm',
+                        '_cw_entity_fields:X': '',
 
-                    '__type:Y': 'File',
-                    '_cw_entity_fields:Y': 'data-subject,described_by_test-object',
-                    'data-subject:Y': (u'coucou.txt', Binary('coucou')),
-                    'described_by_test-object:Y': 'X',
-                    }
-        path, params = self.expect_redirect_handle_request(req, 'edit')
-        self.assertTrue(path.startswith('salesterm/'), path)
-        eid = path.split('/')[1]
-        salesterm = req.entity_from_eid(eid)
-        # The NOT NULL constraint of mandatory relation implies that the File
-        # must be created before the Salesterm, otherwise Salesterm insertion
-        # will fail.
-        # NOTE: sqlite does have NOT NULL constraint, unlike Postgres so the
-        # insertion does not fail and we have to check dumbly that File is
-        # created before.
-        self.assertGreater(salesterm.eid, salesterm.described_by_test[0].eid)
+                        '__type:Y': 'File',
+                        '_cw_entity_fields:Y': 'data-subject,described_by_test-object',
+                        'data-subject:Y': (u'coucou.txt', Binary('coucou')),
+                        'described_by_test-object:Y': 'X',
+                        }
+            path, _params = self.expect_redirect_handle_request(req, 'edit')
+            self.assertTrue(path.startswith('salesterm/'), path)
+            eid = path.split('/')[1]
+            salesterm = req.entity_from_eid(eid)
+            # The NOT NULL constraint of mandatory relation implies that the File
+            # must be created before the Salesterm, otherwise Salesterm insertion
+            # will fail.
+            # NOTE: sqlite does have NOT NULL constraint, unlike Postgres so the
+            # insertion does not fail and we have to check dumbly that File is
+            # created before.
+            self.assertGreater(salesterm.eid, salesterm.described_by_test[0].eid)
 
     def test_create_mandatory_inlined2(self):
-        req = self.request()
-        req.form = {'eid': ['X', 'Y'], '__maineid' : 'X',
-
-                    '__type:X': 'Salesterm',
-                    '_cw_entity_fields:X': 'described_by_test-subject',
-                    'described_by_test-subject:X': 'Y',
-
-                    '__type:Y': 'File',
-                    '_cw_entity_fields:Y': 'data-subject',
-                    'data-subject:Y': (u'coucou.txt', Binary('coucou')),
-                    }
-        path, params = self.expect_redirect_handle_request(req, 'edit')
-        self.assertTrue(path.startswith('salesterm/'), path)
-        eid = path.split('/')[1]
-        salesterm = req.entity_from_eid(eid)
-        # The NOT NULL constraint of mandatory relation implies that the File
-        # must be created before the Salesterm, otherwise Salesterm insertion
-        # will fail.
-        # NOTE: sqlite does have NOT NULL constraint, unlike Postgres so the
-        # insertion does not fail and we have to check dumbly that File is
-        # created before.
-        self.assertGreater(salesterm.eid, salesterm.described_by_test[0].eid)
-
-    def test_edit_mandatory_inlined3_object(self):
-        # non regression test for #3120495. Without the fix, leads to
-        # "unhashable type: 'list'" error
-        req = self.request()
-        cwrelation = u(req.execute('CWEType X WHERE X name "CWSource"')[0][0])
-        req.form = {'eid': [cwrelation], '__maineid' : cwrelation,
-
-                    '__type:'+cwrelation: 'CWEType',
-                    '_cw_entity_fields:'+cwrelation: 'to_entity-object',
-                    'to_entity-object:'+cwrelation: [9999, 9998],
-                    }
-        with self.session.deny_all_hooks_but():
-            path, params = self.expect_redirect_handle_request(req, 'edit')
-        self.assertTrue(path.startswith('cwetype/CWSource'), path)
-
-    def test_edit_multiple_linked(self):
-        req = self.request()
-        peid = u(self.create_user(req, 'adim').eid)
-        req.form = {'eid': [peid, 'Y'], '__maineid': peid,
-
-                    '__type:'+peid: u'CWUser',
-                    '_cw_entity_fields:'+peid: u'surname-subject',
-                    'surname-subject:'+peid: u'Di Masci',
-
-                    '__type:Y': u'EmailAddress',
-                    '_cw_entity_fields:Y': u'address-subject,use_email-object',
-                    'address-subject:Y': u'dima@logilab.fr',
-                    'use_email-object:Y': peid,
-                    }
-        path, params = self.expect_redirect_handle_request(req, 'edit')
-        # should be redirected on the created person
-        self.assertEqual(path, 'cwuser/adim')
-        e = self.execute('Any P WHERE P surname "Di Masci"').get_entity(0, 0)
-        email = e.use_email[0]
-        self.assertEqual(email.address, 'dima@logilab.fr')
-
-        emaileid = u(email.eid)
-        req = self.request()
-        req.form = {'eid': [peid, emaileid],
-
-                    '__type:'+peid: u'CWUser',
-                    '_cw_entity_fields:'+peid: u'surname-subject',
-                    'surname-subject:'+peid: u'Di Masci',
-
-                    '__type:'+emaileid: u'EmailAddress',
-                    '_cw_entity_fields:'+emaileid: u'address-subject,use_email-object',
-                    'address-subject:'+emaileid: u'adim@logilab.fr',
-                    'use_email-object:'+emaileid: peid,
-                    }
-        path, params = self.expect_redirect_handle_request(req, 'edit')
-        email.cw_clear_all_caches()
-        self.assertEqual(email.address, 'adim@logilab.fr')
-
-
-    def test_password_confirm(self):
-        """test creation of two linked entities
-        """
-        user = self.user()
-        req = self.request()
-        req.form = {'eid': 'X',
-                    '__cloned_eid:X': u(user.eid), '__type:X': 'CWUser',
-                    '_cw_entity_fields:X': 'login-subject,upassword-subject',
-                    'login-subject:X': u'toto',
-                    'upassword-subject:X': u'toto',
-                    }
-        with self.assertRaises(ValidationError) as cm:
-            self.ctrl_publish(req)
-        self.assertEqual(cm.exception.errors, {'upassword-subject': u'password and confirmation don\'t match'})
-        req = self.request()
-        req.form = {'__cloned_eid:X': u(user.eid),
-                    'eid': 'X', '__type:X': 'CWUser',
-                    '_cw_entity_fields:X': 'login-subject,upassword-subject',
-                    'login-subject:X': u'toto',
-                    'upassword-subject:X': u'toto',
-                    'upassword-subject-confirm:X': u'tutu',
-                    }
-        with self.assertRaises(ValidationError) as cm:
-            self.ctrl_publish(req)
-        self.assertEqual(cm.exception.errors, {'upassword-subject': u'password and confirmation don\'t match'})
-
-
-    def test_interval_bound_constraint_success(self):
-        feid = self.execute('INSERT File X: X data_name "toto.txt", X data %(data)s',
-                            {'data': Binary('yo')})[0][0]
-        self.commit()
-        req = self.request(rollbackfirst=True)
-        req.form = {'eid': ['X'],
-                    '__type:X': 'Salesterm',
-                    '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
-                    'amount-subject:X': u'-10',
-                    'described_by_test-subject:X': u(feid),
-                }
-        with self.assertRaises(ValidationError) as cm:
-            self.ctrl_publish(req)
-        cm.exception.translate(unicode)
-        self.assertEqual(cm.exception.errors, {'amount-subject': 'value -10 must be >= 0'})
-        req = self.request(rollbackfirst=True)
-        req.form = {'eid': ['X'],
-                    '__type:X': 'Salesterm',
-                    '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
-                    'amount-subject:X': u'110',
-                    'described_by_test-subject:X': u(feid),
-                    }
-        with self.assertRaises(ValidationError) as cm:
-            self.ctrl_publish(req)
-        cm.exception.translate(unicode)
-        self.assertEqual(cm.exception.errors, {'amount-subject': 'value 110 must be <= 100'})
-
-        req = self.request(rollbackfirst=True)
-        req.form = {'eid': ['X'],
-                    '__type:X': 'Salesterm',
-                    '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
-                    'amount-subject:X': u'10',
-                    'described_by_test-subject:X': u(feid),
-                    }
-        self.expect_redirect_handle_request(req, 'edit')
-        # should be redirected on the created
-        #eid = params['rql'].split()[-1]
-        e = self.execute('Salesterm X').get_entity(0, 0)
-        self.assertEqual(e.amount, 10)
-
-    def test_interval_bound_constraint_validateform(self):
-        """Test the FormValidatorController controller on entity with
-        constrained attributes"""
-        feid = self.execute('INSERT File X: X data_name "toto.txt", X data %(data)s',
-                            {'data': Binary('yo')})[0][0]
-        seid = self.request().create_entity('Salesterm', amount=0, described_by_test=feid).eid
-        self.commit()
-
-        # ensure a value that violate a constraint is properly detected
-        req = self.request(rollbackfirst=True)
-        req.form = {'eid': [unicode(seid)],
-                    '__type:%s'%seid: 'Salesterm',
-                    '_cw_entity_fields:%s'%seid: 'amount-subject',
-                    'amount-subject:%s'%seid: u'-10',
-                }
-        self.assertEqual('''<script type="text/javascript">
- window.parent.handleFormValidationResponse('entityForm', null, null, [false, [%s, {"amount-subject": "value -10 must be >= 0"}], null], null);
-</script>'''%seid, self.ctrl_publish(req, 'validateform'))
-
-        # ensure a value that comply a constraint is properly processed
-        req = self.request(rollbackfirst=True)
-        req.form = {'eid': [unicode(seid)],
-                    '__type:%s'%seid: 'Salesterm',
-                    '_cw_entity_fields:%s'%seid: 'amount-subject',
-                    'amount-subject:%s'%seid: u'20',
-                }
-        self.assertEqual('''<script type="text/javascript">
- window.parent.handleFormValidationResponse('entityForm', null, null, [true, "http://testing.fr/cubicweb/view", null], null);
-</script>''', self.ctrl_publish(req, 'validateform'))
-        self.assertEqual(20, self.execute('Any V WHERE X amount V, X eid %(eid)s', {'eid': seid})[0][0])
-
-        req = self.request(rollbackfirst=True)
-        req.form = {'eid': ['X'],
-                    '__type:X': 'Salesterm',
-                    '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
-                    'amount-subject:X': u'0',
-                    'described_by_test-subject:X': u(feid),
-                }
-
-        # ensure a value that is modified in an operation on a modify
-        # hook works as it should (see
-        # https://www.cubicweb.org/ticket/2509729 )
-        class MyOperation(Operation):
-            def precommit_event(self):
-                self.entity.cw_set(amount=-10)
-        class ValidationErrorInOpAfterHook(Hook):
-            __regid__ = 'valerror-op-after-hook'
-            __select__ = Hook.__select__ & is_instance('Salesterm')
-            events = ('after_add_entity',)
-            def __call__(self):
-                MyOperation(self._cw, entity=self.entity)
-
-        with self.temporary_appobjects(ValidationErrorInOpAfterHook):
-            self.assertEqual('''<script type="text/javascript">
- window.parent.handleFormValidationResponse('entityForm', null, null, [false, ["X", {"amount-subject": "value -10 must be >= 0"}], null], null);
-</script>''', self.ctrl_publish(req, 'validateform'))
-
-        self.assertEqual('''<script type="text/javascript">
- window.parent.handleFormValidationResponse('entityForm', null, null, [true, "http://testing.fr/cubicweb/view", null], null);
-</script>''', self.ctrl_publish(req, 'validateform'))
-
-    def test_req_pending_insert(self):
-        """make sure req's pending insertions are taken into account"""
-        tmpgroup = self.request().create_entity('CWGroup', name=u"test")
-        user = self.user()
-        req = self.request(**req_form(user))
-        req.session.data['pending_insert'] = set([(user.eid, 'in_group', tmpgroup.eid)])
-        path, params = self.expect_redirect_handle_request(req, 'edit')
-        usergroups = [gname for gname, in
-                      self.execute('Any N WHERE G name N, U in_group G, U eid %(u)s', {'u': user.eid})]
-        self.assertCountEqual(usergroups, ['managers', 'test'])
-        self.assertEqual(get_pending_inserts(req), [])
-
-    def test_req_pending_delete(self):
-        """make sure req's pending deletions are taken into account"""
-        user = self.user()
-        groupeid = self.execute('INSERT CWGroup G: G name "test", U in_group G WHERE U eid %(x)s',
-                                {'x': user.eid})[0][0]
-        usergroups = [gname for gname, in
-                      self.execute('Any N WHERE G name N, U in_group G, U eid %(u)s', {'u': user.eid})]
-        # just make sure everything was set correctly
-        self.assertCountEqual(usergroups, ['managers', 'test'])
-        # now try to delete the relation
-        req = self.request(**req_form(user))
-        req.session.data['pending_delete'] = set([(user.eid, 'in_group', groupeid)])
-        path, params = self.expect_redirect_handle_request(req, 'edit')
-        usergroups = [gname for gname, in
-                      self.execute('Any N WHERE G name N, U in_group G, U eid %(u)s', {'u': user.eid})]
-        self.assertCountEqual(usergroups, ['managers'])
-        self.assertEqual(get_pending_deletes(req), [])
-
-    def test_redirect_apply_button(self):
-        redirectrql = rql_for_eid(4012) # whatever
-        req = self.request()
-        req.form = {
-            'eid': 'A', '__maineid' : 'A',
-            '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'content-subject,title-subject',
-            'content-subject:A': u'"13:03:43"',
-            'title-subject:A': u'huuu',
-            '__redirectrql': redirectrql,
-            '__redirectvid': 'primary',
-            '__redirectparams': 'toto=tutu&tata=titi',
-            '__form_id': 'edition',
-            '__action_apply': '',
-            }
-        path, params = self.expect_redirect_handle_request(req, 'edit')
-        self.assertTrue(path.startswith('blogentry/'))
-        eid = path.split('/')[1]
-        self.assertEqual(params['vid'], 'edition')
-        self.assertNotEqual(int(eid), 4012)
-        self.assertEqual(params['__redirectrql'], redirectrql)
-        self.assertEqual(params['__redirectvid'], 'primary')
-        self.assertEqual(params['__redirectparams'], 'toto=tutu&tata=titi')
-
-    def test_redirect_ok_button(self):
-        redirectrql = rql_for_eid(4012) # whatever
-        req = self.request()
-        req.form = {
-            'eid': 'A', '__maineid' : 'A',
-            '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'content-subject,title-subject',
-            'content-subject:A': u'"13:03:43"',
-            'title-subject:A': u'huuu',
-            '__redirectrql': redirectrql,
-            '__redirectvid': 'primary',
-            '__redirectparams': 'toto=tutu&tata=titi',
-            '__form_id': 'edition',
-            }
-        path, params = self.expect_redirect_handle_request(req, 'edit')
-        self.assertEqual(path, 'view')
-        self.assertEqual(params['rql'], redirectrql)
-        self.assertEqual(params['vid'], 'primary')
-        self.assertEqual(params['tata'], 'titi')
-        self.assertEqual(params['toto'], 'tutu')
-
-    def test_redirect_delete_button(self):
-        req = self.request()
-        eid = req.create_entity('BlogEntry', title=u'hop', content=u'hop').eid
-        req.form = {'eid': u(eid), '__type:%s'%eid: 'BlogEntry',
-                    '__action_delete': ''}
-        path, params = self.expect_redirect_handle_request(req, 'edit')
-        self.assertEqual(path, 'blogentry')
-        self.assertIn('_cwmsgid', params)
-        eid = req.create_entity('EmailAddress', address=u'hop@logilab.fr').eid
-        self.execute('SET X use_email E WHERE E eid %(e)s, X eid %(x)s',
-                     {'x': self.session.user.eid, 'e': eid})
-        self.commit()
-        req = req
-        req.form = {'eid': u(eid), '__type:%s'%eid: 'EmailAddress',
-                    '__action_delete': ''}
-        path, params = self.expect_redirect_handle_request(req, 'edit')
-        self.assertEqual(path, 'cwuser/admin')
-        self.assertIn('_cwmsgid', params)
-        eid1 = req.create_entity('BlogEntry', title=u'hop', content=u'hop').eid
-        eid2 = req.create_entity('EmailAddress', address=u'hop@logilab.fr').eid
-        req = self.request()
-        req.form = {'eid': [u(eid1), u(eid2)],
-                    '__type:%s'%eid1: 'BlogEntry',
-                    '__type:%s'%eid2: 'EmailAddress',
-                    '__action_delete': ''}
-        path, params = self.expect_redirect_handle_request(req, 'edit')
-        self.assertEqual(path, 'view')
-        self.assertIn('_cwmsgid', params)
-
-    def test_simple_copy(self):
-        req = self.request()
-        blog = req.create_entity('Blog', title=u'my-blog')
-        blogentry = req.create_entity('BlogEntry', title=u'entry1',
-                                      content=u'content1', entry_of=blog)
-        req = self.request()
-        req.form = {'__maineid' : 'X', 'eid': 'X',
-                    '__cloned_eid:X': blogentry.eid, '__type:X': 'BlogEntry',
-                    '_cw_entity_fields:X': 'title-subject,content-subject',
-                    'title-subject:X': u'entry1-copy',
-                    'content-subject:X': u'content1',
-                    }
-        self.expect_redirect_handle_request(req, 'edit')
-        blogentry2 = req.find_one_entity('BlogEntry', title=u'entry1-copy')
-        self.assertEqual(blogentry2.entry_of[0].eid, blog.eid)
-
-    def test_skip_copy_for(self):
-        req = self.request()
-        blog = req.create_entity('Blog', title=u'my-blog')
-        blogentry = req.create_entity('BlogEntry', title=u'entry1',
-                                      content=u'content1', entry_of=blog)
-        blogentry.__class__.cw_skip_copy_for = [('entry_of', 'subject')]
-        try:
-            req = self.request()
-            req.form = {'__maineid' : 'X', 'eid': 'X',
-                        '__cloned_eid:X': blogentry.eid, '__type:X': 'BlogEntry',
-                        '_cw_entity_fields:X': 'title-subject,content-subject',
-                        'title-subject:X': u'entry1-copy',
-                        'content-subject:X': u'content1',
-                        }
-            self.expect_redirect_handle_request(req, 'edit')
-            blogentry2 = req.find_one_entity('BlogEntry', title=u'entry1-copy')
-            # entry_of should not be copied
-            self.assertEqual(len(blogentry2.entry_of), 0)
-        finally:
-            blogentry.__class__.cw_skip_copy_for = []
-
-    def test_nonregr_eetype_etype_editing(self):
-        """non-regression test checking that a manager user can edit a CWEType entity
-        """
-        groupeids = sorted(eid for eid, in self.execute('CWGroup G WHERE G name in ("managers", "users")'))
-        groups = [u(eid) for eid in groupeids]
-        cwetypeeid = self.execute('CWEType X WHERE X name "CWEType"')[0][0]
-        basegroups = [u(eid) for eid, in self.execute('CWGroup G WHERE X read_permission G, X eid %(x)s', {'x': cwetypeeid})]
-        cwetypeeid = u(cwetypeeid)
-        req = self.request()
-        req.form = {
-            'eid':      cwetypeeid,
-            '__type:'+cwetypeeid:  'CWEType',
-            '_cw_entity_fields:'+cwetypeeid: 'name-subject,final-subject,description-subject,read_permission-subject',
-            'name-subject:'+cwetypeeid:     u'CWEType',
-            'final-subject:'+cwetypeeid:    '',
-            'description-subject:'+cwetypeeid:     u'users group',
-            'read_permission-subject:'+cwetypeeid:  groups,
-            }
-        try:
-            path, params = self.expect_redirect_handle_request(req, 'edit')
-            e = self.execute('Any X WHERE X eid %(x)s', {'x': cwetypeeid}).get_entity(0, 0)
-            self.assertEqual(e.name, 'CWEType')
-            self.assertEqual(sorted(g.eid for g in e.read_permission), groupeids)
-        finally:
-            # restore
-            self.execute('SET X read_permission Y WHERE X name "CWEType", Y eid IN (%s), NOT X read_permission Y' % (','.join(basegroups)))
-            self.commit()
-
-    def test_nonregr_strange_text_input(self):
-        """non-regression test checking text input containing "13:03:43"
-
-        this seems to be postgres (tsearch?) specific
-        """
-        req = self.request()
-        req.form = {
-            'eid': 'A', '__maineid' : 'A',
-            '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'title-subject,content-subject',
-            'title-subject:A': u'"13:03:40"',
-            'content-subject:A': u'"13:03:43"',}
-        path, params = self.expect_redirect_handle_request(req, 'edit')
-        self.assertTrue(path.startswith('blogentry/'))
-        eid = path.split('/')[1]
-        e = self.execute('Any C, T WHERE C eid %(x)s, C content T', {'x': eid}).get_entity(0, 0)
-        self.assertEqual(e.title, '"13:03:40"')
-        self.assertEqual(e.content, '"13:03:43"')
-
-
-    def test_nonregr_multiple_empty_email_addr(self):
-        gueid = self.execute('CWGroup G WHERE G name "users"')[0][0]
-        req = self.request()
-        req.form = {'eid': ['X', 'Y'],
-
-                    '__type:X': 'CWUser',
-                    '_cw_entity_fields:X': 'login-subject,upassword-subject,in_group-subject',
-                    'login-subject:X': u'adim',
-                    'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto',
-                    'in_group-subject:X': `gueid`,
-
-                    '__type:Y': 'EmailAddress',
-                    '_cw_entity_fields:Y': 'address-subject,alias-subject,use_email-object',
-                    'address-subject:Y': u'',
-                    'alias-subject:Y': u'',
-                    'use_email-object:Y': 'X',
-                    }
-        with self.assertRaises(ValidationError) as cm:
-            self.ctrl_publish(req)
-        self.assertEqual(cm.exception.errors, {'address-subject': u'required field'})
-
-    def test_nonregr_copy(self):
-        user = self.user()
-        req = self.request()
-        req.form = {'__maineid' : 'X', 'eid': 'X',
-                    '__cloned_eid:X': user.eid, '__type:X': 'CWUser',
-                    '_cw_entity_fields:X': 'login-subject,upassword-subject',
-                    'login-subject:X': u'toto',
-                    'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto',
-                    }
-        path, params = self.expect_redirect_handle_request(req, 'edit')
-        self.assertEqual(path, 'cwuser/toto')
-        e = self.execute('Any X WHERE X is CWUser, X login "toto"').get_entity(0, 0)
-        self.assertEqual(e.login, 'toto')
-        self.assertEqual(e.in_group[0].name, 'managers')
-
-
-    def test_nonregr_rollback_on_validation_error(self):
-        req = self.request()
-        p = self.create_user(req, "doe")
-        # do not try to skip 'primary_email' for this test
-        old_skips = p.__class__.skip_copy_for
-        p.__class__.skip_copy_for = ()
-        try:
-            e = self.request().create_entity('EmailAddress', address=u'doe@doe.com')
-            self.execute('SET P use_email E, P primary_email E WHERE P eid %(p)s, E eid %(e)s',
-                         {'p' : p.eid, 'e' : e.eid})
-            req = self.request()
-            req.form = {'eid': 'X',
-                        '__cloned_eid:X': p.eid, '__type:X': 'CWUser',
-                        '_cw_entity_fields:X': 'login-subject,surname-subject',
-                        'login-subject': u'dodo',
-                        'surname-subject:X': u'Boom',
-                        '__errorurl' : "whatever but required",
-                        }
-            # try to emulate what really happens in the web application
-            # 1/ validate form => EditController.publish raises a ValidationError
-            #    which fires a Redirect
-            # 2/ When re-publishing the copy form, the publisher implicitly commits
-            try:
-                self.app_handle_request(req, 'edit')
-            except Redirect:
-                req = self.request()
-                req.form['rql'] = 'Any X WHERE X eid %s' % p.eid
-                req.form['vid'] = 'copy'
-                self.app_handle_request(req, 'view')
-            rset = self.execute('CWUser P WHERE P surname "Boom"')
-            self.assertEqual(len(rset), 0)
-        finally:
-            p.__class__.skip_copy_for = old_skips
-
-    def test_regr_inlined_forms(self):
-        self.schema['described_by_test'].inlined = False
-        try:
-            req = self.request()
-            req.data['eidmap'] = {}
-            req.data['pending_others'] = set()
-            req.data['pending_inlined'] = {}
+        with self.admin_access.web_request() as req:
             req.form = {'eid': ['X', 'Y'], '__maineid' : 'X',
 
                         '__type:X': 'Salesterm',
@@ -677,25 +210,507 @@
                         '_cw_entity_fields:Y': 'data-subject',
                         'data-subject:Y': (u'coucou.txt', Binary('coucou')),
                         }
-            values_by_eid = dict((eid, req.extract_entity_params(eid, minparams=2))
-                                 for eid in req.edited_eids())
-            editctrl = self.vreg['controllers'].select('edit', req)
-            # don't call publish to enforce select order
-            editctrl.errors = []
-            editctrl._to_create = {}
-            editctrl.edit_entity(values_by_eid['X']) # #3064653 raise ValidationError
-            editctrl.edit_entity(values_by_eid['Y'])
-        finally:
+            path, _params = self.expect_redirect_handle_request(req, 'edit')
+            self.assertTrue(path.startswith('salesterm/'), path)
+            eid = path.split('/')[1]
+            salesterm = req.entity_from_eid(eid)
+            # The NOT NULL constraint of mandatory relation implies that the File
+            # must be created before the Salesterm, otherwise Salesterm insertion
+            # will fail.
+            # NOTE: sqlite does have NOT NULL constraint, unlike Postgres so the
+            # insertion does not fail and we have to check dumbly that File is
+            # created before.
+            self.assertGreater(salesterm.eid, salesterm.described_by_test[0].eid)
+
+    def test_edit_mandatory_inlined3_object(self):
+        # non regression test for #3120495. Without the fix, leads to
+        # "unhashable type: 'list'" error
+        with self.admin_access.web_request() as req:
+            cwrelation = unicode(req.execute('CWEType X WHERE X name "CWSource"')[0][0])
+            req.form = {'eid': [cwrelation], '__maineid' : cwrelation,
+
+                        '__type:'+cwrelation: 'CWEType',
+                        '_cw_entity_fields:'+cwrelation: 'to_entity-object',
+                        'to_entity-object:'+cwrelation: [9999, 9998],
+                        }
+            with req.cnx.deny_all_hooks_but():
+                path, _params = self.expect_redirect_handle_request(req, 'edit')
+            self.assertTrue(path.startswith('cwetype/CWSource'), path)
+
+    def test_edit_multiple_linked(self):
+        with self.admin_access.web_request() as req:
+            peid = unicode(self.create_user(req, 'adim').eid)
+            req.form = {'eid': [peid, 'Y'], '__maineid': peid,
+
+                        '__type:'+peid: u'CWUser',
+                        '_cw_entity_fields:'+peid: u'surname-subject',
+                        'surname-subject:'+peid: u'Di Masci',
+
+                        '__type:Y': u'EmailAddress',
+                        '_cw_entity_fields:Y': u'address-subject,use_email-object',
+                        'address-subject:Y': u'dima@logilab.fr',
+                        'use_email-object:Y': peid,
+                        }
+            path, _params = self.expect_redirect_handle_request(req, 'edit')
+            # should be redirected on the created person
+            self.assertEqual(path, 'cwuser/adim')
+            e = req.execute('Any P WHERE P surname "Di Masci"').get_entity(0, 0)
+            email = e.use_email[0]
+            self.assertEqual(email.address, 'dima@logilab.fr')
+
+        # with self.admin_access.web_request() as req:
+            emaileid = unicode(email.eid)
+            req.form = {'eid': [peid, emaileid],
+
+                        '__type:'+peid: u'CWUser',
+                        '_cw_entity_fields:'+peid: u'surname-subject',
+                        'surname-subject:'+peid: u'Di Masci',
+
+                        '__type:'+emaileid: u'EmailAddress',
+                        '_cw_entity_fields:'+emaileid: u'address-subject,use_email-object',
+                        'address-subject:'+emaileid: u'adim@logilab.fr',
+                        'use_email-object:'+emaileid: peid,
+                        }
+            self.expect_redirect_handle_request(req, 'edit')
+            email.cw_clear_all_caches()
+            self.assertEqual(email.address, 'adim@logilab.fr')
+
+    def test_password_confirm(self):
+        """test creation of two linked entities
+        """
+        with self.admin_access.web_request() as req:
+            user = req.user
+            req.form = {'eid': 'X',
+                        '__cloned_eid:X': unicode(user.eid), '__type:X': 'CWUser',
+                        '_cw_entity_fields:X': 'login-subject,upassword-subject',
+                        'login-subject:X': u'toto',
+                        'upassword-subject:X': u'toto',
+                        }
+            with self.assertRaises(ValidationError) as cm:
+                self.ctrl_publish(req)
+            self.assertEqual({'upassword-subject': u'password and confirmation don\'t match'},
+                             cm.exception.errors)
+            req.form = {'__cloned_eid:X': unicode(user.eid),
+                        'eid': 'X', '__type:X': 'CWUser',
+                        '_cw_entity_fields:X': 'login-subject,upassword-subject',
+                        'login-subject:X': u'toto',
+                        'upassword-subject:X': u'toto',
+                        'upassword-subject-confirm:X': u'tutu',
+                        }
+            with self.assertRaises(ValidationError) as cm:
+                self.ctrl_publish(req)
+            self.assertEqual({'upassword-subject': u'password and confirmation don\'t match'},
+                             cm.exception.errors)
+
+
+    def test_interval_bound_constraint_success(self):
+        with self.admin_access.repo_cnx() as cnx:
+            feid = cnx.execute('INSERT File X: X data_name "toto.txt", X data %(data)s',
+                               {'data': Binary('yo')})[0][0]
+            cnx.commit()
+
+        with self.admin_access.web_request(rollbackfirst=True) as req:
+            req.form = {'eid': ['X'],
+                        '__type:X': 'Salesterm',
+                        '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
+                        'amount-subject:X': u'-10',
+                        'described_by_test-subject:X': unicode(feid),
+                    }
+            with self.assertRaises(ValidationError) as cm:
+                self.ctrl_publish(req)
+            cm.exception.translate(unicode)
+            self.assertEqual({'amount-subject': 'value -10 must be >= 0'},
+                             cm.exception.errors)
+
+        with self.admin_access.web_request(rollbackfirst=True) as req:
+            req.form = {'eid': ['X'],
+                        '__type:X': 'Salesterm',
+                        '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
+                        'amount-subject:X': u'110',
+                        'described_by_test-subject:X': unicode(feid),
+                        }
+            with self.assertRaises(ValidationError) as cm:
+                self.ctrl_publish(req)
+            cm.exception.translate(unicode)
+            self.assertEqual(cm.exception.errors, {'amount-subject': 'value 110 must be <= 100'})
+
+        with self.admin_access.web_request(rollbackfirst=True) as req:
+            req.form = {'eid': ['X'],
+                        '__type:X': 'Salesterm',
+                        '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
+                        'amount-subject:X': u'10',
+                        'described_by_test-subject:X': unicode(feid),
+                        }
+            self.expect_redirect_handle_request(req, 'edit')
+            # should be redirected on the created
+            #eid = params['rql'].split()[-1]
+            e = req.execute('Salesterm X').get_entity(0, 0)
+            self.assertEqual(e.amount, 10)
+
+    def test_interval_bound_constraint_validateform(self):
+        """Test the FormValidatorController controller on entity with
+        constrained attributes"""
+        with self.admin_access.repo_cnx() as cnx:
+            feid = cnx.execute('INSERT File X: X data_name "toto.txt", X data %(data)s',
+                               {'data': Binary('yo')})[0][0]
+            seid = cnx.create_entity('Salesterm', amount=0, described_by_test=feid).eid
+            cnx.commit()
+
+        # ensure a value that violate a constraint is properly detected
+        with self.admin_access.web_request(rollbackfirst=True) as req:
+            req.form = {'eid': [unicode(seid)],
+                        '__type:%s'%seid: 'Salesterm',
+                        '_cw_entity_fields:%s'%seid: 'amount-subject',
+                        'amount-subject:%s'%seid: u'-10',
+                    }
+            self.assertMultiLineEqual('''<script type="text/javascript">
+ window.parent.handleFormValidationResponse('entityForm', null, null, [false, [%s, {"amount-subject": "value -10 must be >= 0"}], null], null);
+</script>'''%seid, self.ctrl_publish(req, 'validateform'))
+
+        # ensure a value that comply a constraint is properly processed
+        with self.admin_access.web_request(rollbackfirst=True) as req:
+            req.form = {'eid': [unicode(seid)],
+                        '__type:%s'%seid: 'Salesterm',
+                        '_cw_entity_fields:%s'%seid: 'amount-subject',
+                        'amount-subject:%s'%seid: u'20',
+                    }
+            self.assertMultiLineEqual('''<script type="text/javascript">
+ window.parent.handleFormValidationResponse('entityForm', null, null, [true, "http://testing.fr/cubicweb/view", null], null);
+</script>''', self.ctrl_publish(req, 'validateform'))
+            self.assertEqual(20, req.execute('Any V WHERE X amount V, X eid %(eid)s',
+                                             {'eid': seid})[0][0])
+
+        with self.admin_access.web_request(rollbackfirst=True) as req:
+            req.form = {'eid': ['X'],
+                        '__type:X': 'Salesterm',
+                        '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
+                        'amount-subject:X': u'0',
+                        'described_by_test-subject:X': unicode(feid),
+                    }
+
+            # ensure a value that is modified in an operation on a modify
+            # hook works as it should (see
+            # https://www.cubicweb.org/ticket/2509729 )
+            class MyOperation(Operation):
+                def precommit_event(self):
+                    self.entity.cw_set(amount=-10)
+            class ValidationErrorInOpAfterHook(Hook):
+                __regid__ = 'valerror-op-after-hook'
+                __select__ = Hook.__select__ & is_instance('Salesterm')
+                events = ('after_add_entity',)
+                def __call__(self):
+                    MyOperation(self._cw, entity=self.entity)
+
+            with self.temporary_appobjects(ValidationErrorInOpAfterHook):
+                self.assertMultiLineEqual('''<script type="text/javascript">
+ window.parent.handleFormValidationResponse('entityForm', null, null, [false, ["X", {"amount-subject": "value -10 must be >= 0"}], null], null);
+</script>''', self.ctrl_publish(req, 'validateform'))
+
+            self.assertMultiLineEqual('''<script type="text/javascript">
+ window.parent.handleFormValidationResponse('entityForm', null, null, [true, "http://testing.fr/cubicweb/view", null], null);
+</script>''', self.ctrl_publish(req, 'validateform'))
+
+    def test_req_pending_insert(self):
+        """make sure req's pending insertions are taken into account"""
+        with self.admin_access.web_request() as req:
+            tmpgroup = req.create_entity('CWGroup', name=u"test")
+            user = req.user
+            req.cnx.commit()
+        with self.admin_access.web_request(**req_form(user)) as req:
+            req.session.data['pending_insert'] = set([(user.eid, 'in_group', tmpgroup.eid)])
+            self.expect_redirect_handle_request(req, 'edit')
+            usergroups = [gname for gname, in
+                          req.execute('Any N WHERE G name N, U in_group G, U eid %(u)s',
+                                      {'u': user.eid})]
+            self.assertCountEqual(usergroups, ['managers', 'test'])
+            self.assertEqual(get_pending_inserts(req), [])
+
+    def test_req_pending_delete(self):
+        """make sure req's pending deletions are taken into account"""
+        with self.admin_access.web_request() as req:
+            user = req.user
+            groupeid = req.execute('INSERT CWGroup G: G name "test", U in_group G WHERE U eid %(x)s',
+                                    {'x': user.eid})[0][0]
+            usergroups = [gname for gname, in
+                          req.execute('Any N WHERE G name N, U in_group G, U eid %(u)s',
+                                      {'u': user.eid})]
+            # just make sure everything was set correctly
+            self.assertCountEqual(usergroups, ['managers', 'test'])
+            req.cnx.commit()
+            # now try to delete the relation
+        with self.admin_access.web_request(**req_form(user)) as req:
+            req.session.data['pending_delete'] = set([(user.eid, 'in_group', groupeid)])
+            self.expect_redirect_handle_request(req, 'edit')
+            usergroups = [gname for gname, in
+                          req.execute('Any N WHERE G name N, U in_group G, U eid %(u)s',
+                                      {'u': user.eid})]
+            self.assertCountEqual(usergroups, ['managers'])
+            self.assertEqual(get_pending_deletes(req), [])
+
+    def test_redirect_apply_button(self):
+        with self.admin_access.web_request() as req:
+            redirectrql = rql_for_eid(4012) # whatever
+            req.form = {
+                'eid': 'A', '__maineid' : 'A',
+                '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'content-subject,title-subject',
+                'content-subject:A': u'"13:03:43"',
+                'title-subject:A': u'huuu',
+                '__redirectrql': redirectrql,
+                '__redirectvid': 'primary',
+                '__redirectparams': 'toto=tutu&tata=titi',
+                '__form_id': 'edition',
+                '__action_apply': '',
+                }
+            path, params = self.expect_redirect_handle_request(req, 'edit')
+            self.assertTrue(path.startswith('blogentry/'))
+            eid = path.split('/')[1]
+            self.assertEqual(params['vid'], 'edition')
+            self.assertNotEqual(int(eid), 4012)
+            self.assertEqual(params['__redirectrql'], redirectrql)
+            self.assertEqual(params['__redirectvid'], 'primary')
+            self.assertEqual(params['__redirectparams'], 'toto=tutu&tata=titi')
+
+    def test_redirect_ok_button(self):
+        with self.admin_access.web_request() as req:
+            redirectrql = rql_for_eid(4012) # whatever
+            req.form = {
+                'eid': 'A', '__maineid' : 'A',
+                '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'content-subject,title-subject',
+                'content-subject:A': u'"13:03:43"',
+                'title-subject:A': u'huuu',
+                '__redirectrql': redirectrql,
+                '__redirectvid': 'primary',
+                '__redirectparams': 'toto=tutu&tata=titi',
+                '__form_id': 'edition',
+                }
+            path, params = self.expect_redirect_handle_request(req, 'edit')
+            self.assertEqual(path, 'view')
+            self.assertEqual(params['rql'], redirectrql)
+            self.assertEqual(params['vid'], 'primary')
+            self.assertEqual(params['tata'], 'titi')
+            self.assertEqual(params['toto'], 'tutu')
+
+    def test_redirect_delete_button(self):
+        with self.admin_access.web_request() as req:
+            eid = req.create_entity('BlogEntry', title=u'hop', content=u'hop').eid
+            req.form = {'eid': unicode(eid), '__type:%s'%eid: 'BlogEntry',
+                        '__action_delete': ''}
+            path, params = self.expect_redirect_handle_request(req, 'edit')
+            self.assertEqual(path, 'blogentry')
+            self.assertIn('_cwmsgid', params)
+            eid = req.create_entity('EmailAddress', address=u'hop@logilab.fr').eid
+            req.execute('SET X use_email E WHERE E eid %(e)s, X eid %(x)s',
+                        {'x': self.session.user.eid, 'e': eid})
+            req.cnx.commit()
+            req.form = {'eid': unicode(eid), '__type:%s'%eid: 'EmailAddress',
+                        '__action_delete': ''}
+            path, params = self.expect_redirect_handle_request(req, 'edit')
+            self.assertEqual(path, 'cwuser/admin')
+            self.assertIn('_cwmsgid', params)
+            eid1 = req.create_entity('BlogEntry', title=u'hop', content=u'hop').eid
+            eid2 = req.create_entity('EmailAddress', address=u'hop@logilab.fr').eid
+            req.form = {'eid': [unicode(eid1), unicode(eid2)],
+                        '__type:%s'%eid1: 'BlogEntry',
+                        '__type:%s'%eid2: 'EmailAddress',
+                        '__action_delete': ''}
+            path, params = self.expect_redirect_handle_request(req, 'edit')
+            self.assertEqual(path, 'view')
+            self.assertIn('_cwmsgid', params)
+
+    def test_simple_copy(self):
+        with self.admin_access.web_request() as req:
+            blog = req.create_entity('Blog', title=u'my-blog')
+            blogentry = req.create_entity('BlogEntry', title=u'entry1',
+                                          content=u'content1', entry_of=blog)
+            req.form = {'__maineid' : 'X', 'eid': 'X',
+                        '__cloned_eid:X': blogentry.eid, '__type:X': 'BlogEntry',
+                        '_cw_entity_fields:X': 'title-subject,content-subject',
+                        'title-subject:X': u'entry1-copy',
+                        'content-subject:X': u'content1',
+                        }
+            self.expect_redirect_handle_request(req, 'edit')
+            blogentry2 = req.find('BlogEntry', title=u'entry1-copy').one()
+            self.assertEqual(blogentry2.entry_of[0].eid, blog.eid)
+
+    def test_skip_copy_for(self):
+        with self.admin_access.web_request() as req:
+            blog = req.create_entity('Blog', title=u'my-blog')
+            blogentry = req.create_entity('BlogEntry', title=u'entry1',
+                                          content=u'content1', entry_of=blog)
+            blogentry.__class__.cw_skip_copy_for = [('entry_of', 'subject')]
+            try:
+                req.form = {'__maineid' : 'X', 'eid': 'X',
+                            '__cloned_eid:X': blogentry.eid, '__type:X': 'BlogEntry',
+                            '_cw_entity_fields:X': 'title-subject,content-subject',
+                            'title-subject:X': u'entry1-copy',
+                            'content-subject:X': u'content1',
+                            }
+                self.expect_redirect_handle_request(req, 'edit')
+                blogentry2 = req.find('BlogEntry', title=u'entry1-copy').one()
+                # entry_of should not be copied
+                self.assertEqual(len(blogentry2.entry_of), 0)
+            finally:
+                blogentry.__class__.cw_skip_copy_for = []
+
+    def test_nonregr_eetype_etype_editing(self):
+        """non-regression test checking that a manager user can edit a CWEType entity
+        """
+        with self.admin_access.web_request() as req:
+            groupeids = sorted(eid
+                               for eid, in req.execute('CWGroup G '
+                                                       'WHERE G name in ("managers", "users")'))
+            groups = [unicode(eid) for eid in groupeids]
+            cwetypeeid = req.execute('CWEType X WHERE X name "CWEType"')[0][0]
+            basegroups = [unicode(eid)
+                          for eid, in req.execute('CWGroup G '
+                                                  'WHERE X read_permission G, X eid %(x)s',
+                                                  {'x': cwetypeeid})]
+            cwetypeeid = unicode(cwetypeeid)
+            req.form = {
+                'eid':      cwetypeeid,
+                '__type:'+cwetypeeid:  'CWEType',
+                '_cw_entity_fields:'+cwetypeeid: 'name-subject,final-subject,description-subject,read_permission-subject',
+                'name-subject:'+cwetypeeid:     u'CWEType',
+                'final-subject:'+cwetypeeid:    '',
+                'description-subject:'+cwetypeeid:     u'users group',
+                'read_permission-subject:'+cwetypeeid:  groups,
+            }
+            try:
+                self.expect_redirect_handle_request(req, 'edit')
+                e = req.execute('Any X WHERE X eid %(x)s', {'x': cwetypeeid}).get_entity(0, 0)
+                self.assertEqual(e.name, 'CWEType')
+                self.assertEqual(sorted(g.eid for g in e.read_permission), groupeids)
+            finally:
+                # restore
+                req.execute('SET X read_permission Y WHERE X name "CWEType", '
+                            'Y eid IN (%s), NOT X read_permission Y' % (','.join(basegroups)))
+                req.cnx.commit()
+
+    def test_nonregr_strange_text_input(self):
+        """non-regression test checking text input containing "13:03:43"
+
+        this seems to be postgres (tsearch?) specific
+        """
+        with self.admin_access.web_request() as req:
+            req.form = {
+                'eid': 'A', '__maineid' : 'A',
+                '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'title-subject,content-subject',
+                'title-subject:A': u'"13:03:40"',
+                'content-subject:A': u'"13:03:43"',}
+            path, _params = self.expect_redirect_handle_request(req, 'edit')
+            self.assertTrue(path.startswith('blogentry/'))
+            eid = path.split('/')[1]
+            e = req.execute('Any C, T WHERE C eid %(x)s, C content T', {'x': eid}).get_entity(0, 0)
+            self.assertEqual(e.title, '"13:03:40"')
+            self.assertEqual(e.content, '"13:03:43"')
+
+
+    def test_nonregr_multiple_empty_email_addr(self):
+        with self.admin_access.web_request() as req:
+            gueid = req.execute('CWGroup G WHERE G name "users"')[0][0]
+            req.form = {'eid': ['X', 'Y'],
+
+                        '__type:X': 'CWUser',
+                        '_cw_entity_fields:X': 'login-subject,upassword-subject,in_group-subject',
+                        'login-subject:X': u'adim',
+                        'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto',
+                        'in_group-subject:X': `gueid`,
+
+                        '__type:Y': 'EmailAddress',
+                        '_cw_entity_fields:Y': 'address-subject,alias-subject,use_email-object',
+                        'address-subject:Y': u'',
+                        'alias-subject:Y': u'',
+                        'use_email-object:Y': 'X',
+                        }
+            with self.assertRaises(ValidationError) as cm:
+                self.ctrl_publish(req)
+            self.assertEqual(cm.exception.errors, {'address-subject': u'required field'})
+
+    def test_nonregr_copy(self):
+        with self.admin_access.web_request() as req:
+            user = req.user
+            req.form = {'__maineid' : 'X', 'eid': 'X',
+                        '__cloned_eid:X': user.eid, '__type:X': 'CWUser',
+                        '_cw_entity_fields:X': 'login-subject,upassword-subject',
+                        'login-subject:X': u'toto',
+                        'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto',
+                        }
+            path, _params = self.expect_redirect_handle_request(req, 'edit')
+            self.assertEqual(path, 'cwuser/toto')
+            e = req.execute('Any X WHERE X is CWUser, X login "toto"').get_entity(0, 0)
+            self.assertEqual(e.login, 'toto')
+            self.assertEqual(e.in_group[0].name, 'managers')
+
+
+    def test_nonregr_rollback_on_validation_error(self):
+        with self.admin_access.web_request() as req:
+            p = self.create_user(req, "doe")
+            # do not try to skip 'primary_email' for this test
+            old_skips = p.__class__.skip_copy_for
+            p.__class__.skip_copy_for = ()
+            try:
+                e = req.create_entity('EmailAddress', address=u'doe@doe.com')
+                req.execute('SET P use_email E, P primary_email E WHERE P eid %(p)s, E eid %(e)s',
+                            {'p' : p.eid, 'e' : e.eid})
+                req.form = {'eid': 'X',
+                            '__cloned_eid:X': p.eid, '__type:X': 'CWUser',
+                            '_cw_entity_fields:X': 'login-subject,surname-subject',
+                            'login-subject': u'dodo',
+                            'surname-subject:X': u'Boom',
+                            '__errorurl' : "whatever but required",
+                            }
+                # try to emulate what really happens in the web application
+                # 1/ validate form => EditController.publish raises a ValidationError
+                #    which fires a Redirect
+                # 2/ When re-publishing the copy form, the publisher implicitly commits
+                try:
+                    self.app_handle_request(req, 'edit')
+                except Redirect:
+                    req.form['rql'] = 'Any X WHERE X eid %s' % p.eid
+                    req.form['vid'] = 'copy'
+                    self.app_handle_request(req, 'view')
+                rset = req.execute('CWUser P WHERE P surname "Boom"')
+                self.assertEqual(len(rset), 0)
+            finally:
+                p.__class__.skip_copy_for = old_skips
+
+    def test_regr_inlined_forms(self):
+        with self.admin_access.web_request() as req:
             self.schema['described_by_test'].inlined = False
+            try:
+                req.data['eidmap'] = {}
+                req.data['pending_others'] = set()
+                req.data['pending_inlined'] = {}
+                req.form = {'eid': ['X', 'Y'], '__maineid' : 'X',
+
+                            '__type:X': 'Salesterm',
+                            '_cw_entity_fields:X': 'described_by_test-subject',
+                            'described_by_test-subject:X': 'Y',
+
+                            '__type:Y': 'File',
+                            '_cw_entity_fields:Y': 'data-subject',
+                            'data-subject:Y': (u'coucou.txt', Binary('coucou')),
+                            }
+                values_by_eid = dict((eid, req.extract_entity_params(eid, minparams=2))
+                                     for eid in req.edited_eids())
+                editctrl = self.vreg['controllers'].select('edit', req)
+                # don't call publish to enforce select order
+                editctrl.errors = []
+                editctrl._to_create = {}
+                editctrl.edit_entity(values_by_eid['X']) # #3064653 raise ValidationError
+                editctrl.edit_entity(values_by_eid['Y'])
+            finally:
+                self.schema['described_by_test'].inlined = False
 
 
 class ReportBugControllerTC(CubicWebTC):
 
     def test_usable_by_guest(self):
-        self.login('anon')
-        self.assertRaises(NoSelectableObject,
-                          self.vreg['controllers'].select, 'reportbug', self.request())
-        self.vreg['controllers'].select('reportbug', self.request(description='hop'))
+        with self.new_access('anon').web_request() as req:
+            self.assertRaises(NoSelectableObject,
+                              self.vreg['controllers'].select, 'reportbug', req)
+        with self.new_access('anon').web_request(description='hop') as req:
+            self.vreg['controllers'].select('reportbug', req)
 
 
 class AjaxControllerTC(CubicWebTC):
@@ -706,21 +721,21 @@
         return self.vreg['controllers'].select(self.tested_controller, req)
 
     def setup_database(self):
-        req = self.request()
-        self.pytag = req.create_entity('Tag', name=u'python')
-        self.cubicwebtag = req.create_entity('Tag', name=u'cubicweb')
-        self.john = self.create_user(req, u'John')
-
+        with self.admin_access.repo_cnx() as cnx:
+            self.pytag = cnx.create_entity('Tag', name=u'python')
+            self.cubicwebtag = cnx.create_entity('Tag', name=u'cubicweb')
+            self.john = self.create_user(cnx, u'John')
+            cnx.commit()
 
     ## tests ##################################################################
     def test_simple_exec(self):
-        req = self.request(rql='CWUser P WHERE P login "John"',
-                           pageid='123', fname='view')
-        ctrl = self.ctrl(req)
-        rset = self.john.as_rset()
-        rset.req = req
-        source = ctrl.publish()
-        self.assertTrue(source.startswith('<div>'))
+        with self.admin_access.web_request(rql='CWUser P WHERE P login "John"',
+                                           pageid='123', fname='view') as req:
+            ctrl = self.ctrl(req)
+            rset = self.john.as_rset()
+            rset.req = req
+            source = ctrl.publish()
+            self.assertTrue(source.startswith('<div>'))
 
 #     def test_json_exec(self):
 #         rql = 'Any T,N WHERE T is Tag, T name N'
@@ -729,92 +744,94 @@
 #                           json_dumps(self.execute(rql).rows))
 
     def test_remote_add_existing_tag(self):
-        self.remote_call('tag_entity', self.john.eid, ['python'])
-        self.assertCountEqual(
-            [tname for tname, in self.execute('Any N WHERE T is Tag, T name N')],
-            ['python', 'cubicweb'])
-        self.assertEqual(
-            self.execute('Any N WHERE T tags P, P is CWUser, T name N').rows,
-            [['python']])
+        with self.remote_calling('tag_entity', self.john.eid, ['python']) as (_, req):
+            self.assertCountEqual(
+                [tname for tname, in req.execute('Any N WHERE T is Tag, T name N')],
+                ['python', 'cubicweb'])
+            self.assertEqual(
+                req.execute('Any N WHERE T tags P, P is CWUser, T name N').rows,
+                [['python']])
 
     def test_remote_add_new_tag(self):
-        self.remote_call('tag_entity', self.john.eid, ['javascript'])
-        self.assertCountEqual(
-            [tname for tname, in self.execute('Any N WHERE T is Tag, T name N')],
-            ['python', 'cubicweb', 'javascript'])
-        self.assertEqual(
-            self.execute('Any N WHERE T tags P, P is CWUser, T name N').rows,
-            [['javascript']])
+        with self.remote_calling('tag_entity', self.john.eid, ['javascript']) as (_, req):
+            self.assertCountEqual(
+                [tname for tname, in req.execute('Any N WHERE T is Tag, T name N')],
+                ['python', 'cubicweb', 'javascript'])
+            self.assertEqual(
+                req.execute('Any N WHERE T tags P, P is CWUser, T name N').rows,
+                [['javascript']])
 
     def test_pending_insertion(self):
-        res, req = self.remote_call('add_pending_inserts', [['12', 'tags', '13']])
-        deletes = get_pending_deletes(req)
-        self.assertEqual(deletes, [])
-        inserts = get_pending_inserts(req)
-        self.assertEqual(inserts, ['12:tags:13'])
-        res, req = self.remote_call('add_pending_inserts', [['12', 'tags', '14']])
-        deletes = get_pending_deletes(req)
-        self.assertEqual(deletes, [])
-        inserts = get_pending_inserts(req)
-        self.assertEqual(inserts, ['12:tags:13', '12:tags:14'])
-        inserts = get_pending_inserts(req, 12)
-        self.assertEqual(inserts, ['12:tags:13', '12:tags:14'])
-        inserts = get_pending_inserts(req, 13)
-        self.assertEqual(inserts, ['12:tags:13'])
-        inserts = get_pending_inserts(req, 14)
-        self.assertEqual(inserts, ['12:tags:14'])
-        req.remove_pending_operations()
+        with self.remote_calling('add_pending_inserts', [['12', 'tags', '13']]) as (_, req):
+            deletes = get_pending_deletes(req)
+            self.assertEqual(deletes, [])
+            inserts = get_pending_inserts(req)
+            self.assertEqual(inserts, ['12:tags:13'])
+        with self.remote_calling('add_pending_inserts', [['12', 'tags', '14']]) as (_, req):
+            deletes = get_pending_deletes(req)
+            self.assertEqual(deletes, [])
+            inserts = get_pending_inserts(req)
+            self.assertEqual(inserts, ['12:tags:13', '12:tags:14'])
+            inserts = get_pending_inserts(req, 12)
+            self.assertEqual(inserts, ['12:tags:13', '12:tags:14'])
+            inserts = get_pending_inserts(req, 13)
+            self.assertEqual(inserts, ['12:tags:13'])
+            inserts = get_pending_inserts(req, 14)
+            self.assertEqual(inserts, ['12:tags:14'])
+            req.remove_pending_operations()
 
     def test_pending_deletion(self):
-        res, req = self.remote_call('add_pending_delete', ['12', 'tags', '13'])
-        inserts = get_pending_inserts(req)
-        self.assertEqual(inserts, [])
-        deletes = get_pending_deletes(req)
-        self.assertEqual(deletes, ['12:tags:13'])
-        res, req = self.remote_call('add_pending_delete', ['12', 'tags', '14'])
-        inserts = get_pending_inserts(req)
-        self.assertEqual(inserts, [])
-        deletes = get_pending_deletes(req)
-        self.assertEqual(deletes, ['12:tags:13', '12:tags:14'])
-        deletes = get_pending_deletes(req, 12)
-        self.assertEqual(deletes, ['12:tags:13', '12:tags:14'])
-        deletes = get_pending_deletes(req, 13)
-        self.assertEqual(deletes, ['12:tags:13'])
-        deletes = get_pending_deletes(req, 14)
-        self.assertEqual(deletes, ['12:tags:14'])
-        req.remove_pending_operations()
+        with self.remote_calling('add_pending_delete', ['12', 'tags', '13']) as (_, req):
+            inserts = get_pending_inserts(req)
+            self.assertEqual(inserts, [])
+            deletes = get_pending_deletes(req)
+            self.assertEqual(deletes, ['12:tags:13'])
+        with self.remote_calling('add_pending_delete', ['12', 'tags', '14']) as (_, req):
+            inserts = get_pending_inserts(req)
+            self.assertEqual(inserts, [])
+            deletes = get_pending_deletes(req)
+            self.assertEqual(deletes, ['12:tags:13', '12:tags:14'])
+            deletes = get_pending_deletes(req, 12)
+            self.assertEqual(deletes, ['12:tags:13', '12:tags:14'])
+            deletes = get_pending_deletes(req, 13)
+            self.assertEqual(deletes, ['12:tags:13'])
+            deletes = get_pending_deletes(req, 14)
+            self.assertEqual(deletes, ['12:tags:14'])
+            req.remove_pending_operations()
 
     def test_remove_pending_operations(self):
-        self.remote_call('add_pending_delete', ['12', 'tags', '13'])
-        _, req = self.remote_call('add_pending_inserts', [['12', 'tags', '14']])
-        inserts = get_pending_inserts(req)
-        self.assertEqual(inserts, ['12:tags:14'])
-        deletes = get_pending_deletes(req)
-        self.assertEqual(deletes, ['12:tags:13'])
-        req.remove_pending_operations()
-        self.assertEqual(get_pending_deletes(req), [])
-        self.assertEqual(get_pending_inserts(req), [])
-
+        with self.remote_calling('add_pending_delete', ['12', 'tags', '13']):
+            pass
+        with self.remote_calling('add_pending_inserts', [['12', 'tags', '14']]) as (_, req):
+            inserts = get_pending_inserts(req)
+            self.assertEqual(inserts, ['12:tags:14'])
+            deletes = get_pending_deletes(req)
+            self.assertEqual(deletes, ['12:tags:13'])
+            req.remove_pending_operations()
+            self.assertEqual(get_pending_deletes(req), [])
+            self.assertEqual(get_pending_inserts(req), [])
 
     def test_add_inserts(self):
-        res, req = self.remote_call('add_pending_inserts',
-                                    [('12', 'tags', '13'), ('12', 'tags', '14')])
-        inserts = get_pending_inserts(req)
-        self.assertEqual(inserts, ['12:tags:13', '12:tags:14'])
-        req.remove_pending_operations()
+        with self.remote_calling('add_pending_inserts',
+                                 [('12', 'tags', '13'), ('12', 'tags', '14')]) as (_, req):
+            inserts = get_pending_inserts(req)
+            self.assertEqual(inserts, ['12:tags:13', '12:tags:14'])
+            req.remove_pending_operations()
 
 
     # silly tests
     def test_external_resource(self):
-        self.assertEqual(self.remote_call('external_resource', 'RSS_LOGO')[0],
-                          json_dumps(self.config.uiprops['RSS_LOGO']))
+        with self.remote_calling('external_resource', 'RSS_LOGO') as (res, _):
+            self.assertEqual(json_dumps(self.config.uiprops['RSS_LOGO']),
+                             res)
+
     def test_i18n(self):
-        self.assertEqual(self.remote_call('i18n', ['bimboom'])[0],
-                          json_dumps(['bimboom']))
+        with self.remote_calling('i18n', ['bimboom']) as (res, _):
+            self.assertEqual(json_dumps(['bimboom']), res)
 
     def test_format_date(self):
-        self.assertEqual(self.remote_call('format_date', '2007-01-01 12:00:00')[0],
-                          json_dumps('2007/01/01'))
+        with self.remote_calling('format_date', '2007-01-01 12:00:00') as (res, _):
+            self.assertEqual(json_dumps('2007/01/01'), res)
 
     def test_ajaxfunc_noparameter(self):
         @ajaxfunc
@@ -826,9 +843,9 @@
         self.assertEqual(appobject.__regid__, 'foo')
         self.assertEqual(appobject.check_pageid, False)
         self.assertEqual(appobject.output_type, None)
-        req = self.request()
-        f = appobject(req)
-        self.assertEqual(f(12, 13), 'hello')
+        with self.admin_access.web_request() as req:
+            f = appobject(req)
+            self.assertEqual(f(12, 13), 'hello')
 
     def test_ajaxfunc_checkpageid(self):
         @ajaxfunc(check_pageid=True)
@@ -841,9 +858,9 @@
         self.assertEqual(appobject.check_pageid, True)
         self.assertEqual(appobject.output_type, None)
         # no pageid
-        req = self.request()
-        f = appobject(req)
-        self.assertRaises(RemoteCallFailed, f, 12, 13)
+        with self.admin_access.web_request() as req:
+            f = appobject(req)
+            self.assertRaises(RemoteCallFailed, f, 12, 13)
 
     def test_ajaxfunc_json(self):
         @ajaxfunc(output_type='json')
@@ -856,9 +873,9 @@
         self.assertEqual(appobject.check_pageid, False)
         self.assertEqual(appobject.output_type, 'json')
         # no pageid
-        req = self.request()
-        f = appobject(req)
-        self.assertEqual(f(12, 13), '25')
+        with self.admin_access.web_request() as req:
+            f = appobject(req)
+            self.assertEqual(f(12, 13), '25')
 
 
 class JSonControllerTC(AjaxControllerTC):
@@ -879,38 +896,44 @@
                 delattr(JSonController, funcname)
 
     def test_monkeypatch_jsoncontroller(self):
-        self.assertRaises(RemoteCallFailed, self.remote_call, 'foo')
+        with self.assertRaises(RemoteCallFailed):
+            with self.remote_calling('foo'):
+                pass
         @monkeypatch(JSonController)
         def js_foo(self):
             return u'hello'
-        res, req = self.remote_call('foo')
-        self.assertEqual(res, u'hello')
+        with self.remote_calling('foo') as (res, _):
+            self.assertEqual(res, u'hello')
 
     def test_monkeypatch_jsoncontroller_xhtmlize(self):
-        self.assertRaises(RemoteCallFailed, self.remote_call, 'foo')
+        with self.assertRaises(RemoteCallFailed):
+            with self.remote_calling('foo'):
+                pass
         @monkeypatch(JSonController)
         @xhtmlize
         def js_foo(self):
             return u'hello'
-        res, req = self.remote_call('foo')
-        self.assertEqual(u'<div>hello</div>', res)
+        with self.remote_calling('foo') as (res, _):
+            self.assertEqual(u'<div>hello</div>', res)
 
     def test_monkeypatch_jsoncontroller_jsonize(self):
-        self.assertRaises(RemoteCallFailed, self.remote_call, 'foo')
+        with self.assertRaises(RemoteCallFailed):
+            with self.remote_calling('foo'):
+                pass
         @monkeypatch(JSonController)
         @jsonize
         def js_foo(self):
             return 12
-        res, req = self.remote_call('foo')
-        self.assertEqual(res, '12')
+        with self.remote_calling('foo') as (res, _):
+            self.assertEqual(res, '12')
 
     def test_monkeypatch_jsoncontroller_stdfunc(self):
         @monkeypatch(JSonController)
         @jsonize
         def js_reledit_form(self):
             return 12
-        res, req = self.remote_call('reledit_form')
-        self.assertEqual(res, '12')
+        with self.remote_calling('reledit_form') as (res, _):
+            self.assertEqual(res, '12')
 
 
 class UndoControllerTC(CubicWebTC):
@@ -926,75 +949,76 @@
         super(UndoControllerTC, self).tearDown()
         cubicweb.server.session.Connection = OldConnection
 
-
     def setup_database(self):
-        req = self.request()
-        self.toto = self.create_user(req, 'toto', password='toto', groups=('users',),
-                                     commit=False)
-        self.txuuid_toto = self.commit()
-        self.toto_email = self.session.create_entity('EmailAddress',
-                                       address=u'toto@logilab.org',
-                                       reverse_use_email=self.toto)
-        self.txuuid_toto_email = self.commit()
+        with self.admin_access.repo_cnx() as cnx:
+            self.toto = self.create_user(cnx, 'toto',
+                                         password='toto',
+                                         groups=('users',),
+                                         commit=False)
+            self.txuuid_toto = cnx.commit()
+            self.toto_email = cnx.create_entity('EmailAddress',
+                                                address=u'toto@logilab.org',
+                                                reverse_use_email=self.toto)
+            self.txuuid_toto_email = cnx.commit()
 
     def test_no_such_transaction(self):
-        req = self.request()
-        txuuid = u"12345acbd"
-        req.form['txuuid'] = txuuid
-        controller = self.vreg['controllers'].select('undo', req)
-        with self.assertRaises(tx.NoSuchTransaction) as cm:
-            result = controller.publish(rset=None)
-        self.assertEqual(cm.exception.txuuid, txuuid)
+        with self.admin_access.web_request() as req:
+            txuuid = u"12345acbd"
+            req.form['txuuid'] = txuuid
+            controller = self.vreg['controllers'].select('undo', req)
+            with self.assertRaises(tx.NoSuchTransaction) as cm:
+                result = controller.publish(rset=None)
+            self.assertEqual(cm.exception.txuuid, txuuid)
 
     def assertURLPath(self, url, expected_path, expected_params=None):
         """ This assert that the path part of `url` matches  expected path
 
         TODO : implement assertion on the expected_params too
         """
-        req = self.request()
-        scheme, netloc, path, query, fragment = urlsplit(url)
-        query_dict = url_parse_query(query)
-        expected_url = urljoin(req.base_url(), expected_path)
-        self.assertEqual( urlunsplit((scheme, netloc, path, None, None)), expected_url)
+        with self.admin_access.web_request() as req:
+            scheme, netloc, path, query, fragment = urlsplit(url)
+            query_dict = url_parse_query(query)
+            expected_url = urljoin(req.base_url(), expected_path)
+            self.assertEqual( urlunsplit((scheme, netloc, path, None, None)), expected_url)
 
     def test_redirect_redirectpath(self):
         "Check that the potential __redirectpath is honored"
-        req = self.request()
-        txuuid = self.txuuid_toto_email
-        req.form['txuuid'] = txuuid
-        rpath = "toto"
-        req.form['__redirectpath'] = rpath
-        controller = self.vreg['controllers'].select('undo', req)
-        with self.assertRaises(Redirect) as cm:
-            result = controller.publish(rset=None)
-        self.assertURLPath(cm.exception.location, rpath)
+        with self.admin_access.web_request() as req:
+            txuuid = self.txuuid_toto_email
+            req.form['txuuid'] = txuuid
+            rpath = "toto"
+            req.form['__redirectpath'] = rpath
+            controller = self.vreg['controllers'].select('undo', req)
+            with self.assertRaises(Redirect) as cm:
+                result = controller.publish(rset=None)
+            self.assertURLPath(cm.exception.location, rpath)
 
     def test_redirect_default(self):
-        req = self.request()
-        txuuid = self.txuuid_toto_email
-        req.form['txuuid'] = txuuid
-        req.session.data['breadcrumbs'] = [ urljoin(req.base_url(), path)
-                                            for path in ('tata', 'toto',)]
-        controller = self.vreg['controllers'].select('undo', req)
-        with self.assertRaises(Redirect) as cm:
-            result = controller.publish(rset=None)
-        self.assertURLPath(cm.exception.location, 'toto')
+        with self.admin_access.web_request() as req:
+            txuuid = self.txuuid_toto_email
+            req.form['txuuid'] = txuuid
+            req.session.data['breadcrumbs'] = [ urljoin(req.base_url(), path)
+                                                for path in ('tata', 'toto',)]
+            controller = self.vreg['controllers'].select('undo', req)
+            with self.assertRaises(Redirect) as cm:
+                result = controller.publish(rset=None)
+            self.assertURLPath(cm.exception.location, 'toto')
 
 
 class LoginControllerTC(CubicWebTC):
 
     def test_login_with_dest(self):
-        req = self.request()
-        req.form = {'postlogin_path': 'elephants/babar'}
-        with self.assertRaises(Redirect) as cm:
-            self.ctrl_publish(req, ctrl='login')
-        self.assertEqual(req.build_url('elephants/babar'), cm.exception.location)
+        with self.admin_access.web_request() as req:
+            req.form = {'postlogin_path': 'elephants/babar'}
+            with self.assertRaises(Redirect) as cm:
+                self.ctrl_publish(req, ctrl='login')
+            self.assertEqual(req.build_url('elephants/babar'), cm.exception.location)
 
     def test_login_no_dest(self):
-        req = self.request()
-        with self.assertRaises(Redirect) as cm:
-            self.ctrl_publish(req, ctrl='login')
-        self.assertEqual(req.base_url(), cm.exception.location)
+        with self.admin_access.web_request() as req:
+            with self.assertRaises(Redirect) as cm:
+                self.ctrl_publish(req, ctrl='login')
+            self.assertEqual(req.base_url(), cm.exception.location)
 
 if __name__ == '__main__':
     unittest_main()
--- a/web/test/unittest_views_basetemplates.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/test/unittest_views_basetemplates.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -18,7 +18,6 @@
 
 from cubicweb.devtools.testlib import CubicWebTC
 from cubicweb.devtools.htmlparser import XMLValidator
-from cubicweb.dbapi import DBAPISession
 
 
 class LogFormTemplateTC(CubicWebTC):
@@ -39,7 +38,8 @@
 class MainNoTopTemplateTC(CubicWebTC):
 
     def test_valid_xhtml(self):
-        self.view('index', template='main-no-top')
+        with self.admin_access.web_request() as req:
+            self.view('index', template='main-no-top', req=req)
 
 
 if __name__ == '__main__':
--- a/web/test/unittest_views_baseviews.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/test/unittest_views_baseviews.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -22,7 +22,6 @@
 from cubicweb.devtools.testlib import CubicWebTC
 from cubicweb.utils import json
 from cubicweb.view import StartupView, TRANSITIONAL_DOCTYPE
-from cubicweb.web.htmlwidgets import TableWidget
 from cubicweb.web.views import vid_from_rset
 
 def loadjson(value):
@@ -31,90 +30,85 @@
 class VidFromRsetTC(CubicWebTC):
 
     def test_no_rset(self):
-        req = self.request()
-        self.assertEqual(vid_from_rset(req, None, self.schema), 'index')
+        with self.admin_access.web_request() as req:
+            self.assertEqual(vid_from_rset(req, None, self.schema), 'index')
 
     def test_no_entity(self):
-        req = self.request()
-        rset = self.execute('Any X WHERE X login "blabla"')
-        self.assertEqual(vid_from_rset(req, rset, self.schema), 'noresult')
+        with self.admin_access.web_request() as req:
+            rset = req.execute('Any X WHERE X login "blabla"')
+            self.assertEqual(vid_from_rset(req, rset, self.schema), 'noresult')
 
     def test_one_entity(self):
-        req = self.request()
-        rset = self.execute('Any X WHERE X login "admin"')
-        self.assertEqual(vid_from_rset(req, rset, self.schema), 'primary')
-        rset = self.execute('Any X, L WHERE X login "admin", X login L')
-        self.assertEqual(vid_from_rset(req, rset, self.schema), 'primary')
-        req.search_state = ('pasnormal',)
-        rset = self.execute('Any X WHERE X login "admin"')
-        self.assertEqual(vid_from_rset(req, rset, self.schema), 'outofcontext-search')
+        with self.admin_access.web_request() as req:
+            rset = req.execute('Any X WHERE X login "admin"')
+            self.assertEqual(vid_from_rset(req, rset, self.schema), 'primary')
+            rset = req.execute('Any X, L WHERE X login "admin", X login L')
+            self.assertEqual(vid_from_rset(req, rset, self.schema), 'primary')
+            req.search_state = ('pasnormal',)
+            rset = req.execute('Any X WHERE X login "admin"')
+            self.assertEqual(vid_from_rset(req, rset, self.schema), 'outofcontext-search')
 
     def test_one_entity_eid(self):
-        req = self.request()
-        rset = self.execute('Any X WHERE X eid 1')
-        self.assertEqual(vid_from_rset(req, rset, self.schema), 'primary')
+        with self.admin_access.web_request() as req:
+            rset = req.execute('Any X WHERE X eid 1')
+            self.assertEqual(vid_from_rset(req, rset, self.schema), 'primary')
 
     def test_more_than_one_entity_same_type(self):
-        req = self.request()
-        rset = self.execute('Any X WHERE X is CWUser')
-        self.assertEqual(vid_from_rset(req, rset, self.schema), 'sameetypelist')
-        rset = self.execute('Any X, L WHERE X login L')
-        self.assertEqual(vid_from_rset(req, rset, self.schema), 'sameetypelist')
+        with self.admin_access.web_request() as req:
+            rset = req.execute('Any X WHERE X is CWUser')
+            self.assertEqual(vid_from_rset(req, rset, self.schema), 'sameetypelist')
+            rset = req.execute('Any X, L WHERE X login L')
+            self.assertEqual(vid_from_rset(req, rset, self.schema), 'sameetypelist')
 
     def test_more_than_one_entity_diff_type(self):
-        req = self.request()
-        rset = self.execute('Any X WHERE X is IN (CWUser, CWGroup)')
-        self.assertEqual(vid_from_rset(req, rset, self.schema), 'list')
+        with self.admin_access.web_request() as req:
+            rset = req.execute('Any X WHERE X is IN (CWUser, CWGroup)')
+            self.assertEqual(vid_from_rset(req, rset, self.schema), 'list')
 
     def test_more_than_one_entity_by_row(self):
-        req = self.request()
-        rset = self.execute('Any X, G WHERE X in_group G')
-        self.assertEqual(vid_from_rset(req, rset, self.schema), 'table')
+        with self.admin_access.web_request() as req:
+            rset = req.execute('Any X, G WHERE X in_group G')
+            self.assertEqual(vid_from_rset(req, rset, self.schema), 'table')
 
     def test_more_than_one_entity_by_row_2(self):
-        req = self.request()
-        rset = self.execute('Any X, GN WHERE X in_group G, G name GN')
-        self.assertEqual(vid_from_rset(req, rset, self.schema), 'table')
+        with self.admin_access.web_request() as req:
+            rset = req.execute('Any X, GN WHERE X in_group G, G name GN')
+            self.assertEqual(vid_from_rset(req, rset, self.schema), 'table')
 
     def test_aggregat(self):
-        req = self.request()
-        rset = self.execute('Any X, COUNT(T) GROUPBY X WHERE X is T')
-        self.assertEqual(vid_from_rset(req, rset, self.schema), 'table')
-        rset = self.execute('Any MAX(X) WHERE X is CWUser')
-        self.assertEqual(vid_from_rset(req, rset, self.schema), 'table')
+        with self.admin_access.web_request() as req:
+            rset = req.execute('Any X, COUNT(T) GROUPBY X WHERE X is T')
+            self.assertEqual(vid_from_rset(req, rset, self.schema), 'table')
+            rset = req.execute('Any MAX(X) WHERE X is CWUser')
+            self.assertEqual(vid_from_rset(req, rset, self.schema), 'table')
 
     def test_subquery(self):
-        rset = self.execute(
+        with self.admin_access.web_request() as req:
+            rset = req.execute(
 'DISTINCT Any X,N ORDERBY N '
 'WITH X,N BEING ('
 '     (DISTINCT Any P,N WHERE P is CWUser, P login N)'
 '       UNION'
 '     (DISTINCT Any W,N WHERE W is CWGroup, W name N))')
-        req = self.request()
-        self.assertEqual(vid_from_rset(req, rset, self.schema), 'table')
+            self.assertEqual(vid_from_rset(req, rset, self.schema), 'table')
 
 
 class TableViewTC(CubicWebTC):
 
-    def _prepare_entity(self):
-        req = self.request()
+    def _prepare_entity(self, req):
         e = req.create_entity("State", name=u'<toto>', description=u'loo"ong blabla')
-        rset = req.execute('Any X, D, CD, NOW - CD WHERE X is State, X description D, X creation_date CD, X eid %(x)s',
+        rset = req.execute('Any X, D, CD, NOW - CD WHERE X is State, '
+                           'X description D, X creation_date CD, X eid %(x)s',
                            {'x': e.eid})
         view = self.vreg['views'].select('table', req, rset=rset)
         return e, rset, view
 
-    def test_headers(self):
-        self.skipTest('implement me')
-
     def test_sortvalue(self):
-        e, _, view = self._prepare_entity()
-        colrenderers = view.build_column_renderers()[:3]
-        self.assertListEqual([renderer.sortvalue(0) for renderer in colrenderers],
-                             [u'<toto>', u'loo"ong blabla', e.creation_date])
-        # XXX sqlite does not handle Interval correctly
-        # value = loadjson(view.sortvalue(0, 3))
-        # self.assertAlmostEquals(value, rset.rows[0][3].seconds)
+        with self.admin_access.web_request() as req:
+            e, _, view = self._prepare_entity(req)
+            colrenderers = view.build_column_renderers()[:3]
+            self.assertListEqual([renderer.sortvalue(0) for renderer in colrenderers],
+                                 [u'<toto>', u'loo"ong blabla', e.creation_date])
 
 
 class HTMLStreamTests(CubicWebTC):
@@ -129,11 +123,15 @@
             def call(self):
                 self._cw.set_doctype('<!DOCTYPE html>')
 
-        with self.temporary_appobjects(MyView):
-            html_source = self.view('my-view').source
-            source_lines = [line.strip() for line in html_source.splitlines(False)
-                            if line.strip()]
-            self.assertListEqual(['<!DOCTYPE html>', '<html xmlns:cubicweb="http://www.cubicweb.org" lang="en">'], source_lines[:2])
+        with self.admin_access.web_request() as req:
+            with self.temporary_appobjects(MyView):
+                html_source = self.view('my-view', req=req).source
+                source_lines = [line.strip()
+                                for line in html_source.splitlines(False)
+                                if line.strip()]
+                self.assertListEqual(['<!DOCTYPE html>',
+                                      '<html xmlns:cubicweb="http://www.cubicweb.org" lang="en">'],
+                                     source_lines[:2])
 
     def test_set_doctype_no_reset_xmldecl(self):
         """
@@ -147,12 +145,16 @@
                 self._cw.set_doctype(html_doctype)
                 self._cw.main_stream.set_htmlattrs([('lang', 'cz')])
 
-        with self.temporary_appobjects(MyView):
-            html_source = self.view('my-view').source
-            source_lines = [line.strip() for line in html_source.splitlines(False)
-                            if line.strip()]
-            self.assertListEqual([html_doctype, '<html xmlns:cubicweb="http://www.cubicweb.org" lang="cz">', '<head>'],
-                                 source_lines[:3])
+        with self.admin_access.web_request() as req:
+            with self.temporary_appobjects(MyView):
+                html_source = self.view('my-view', req=req).source
+                source_lines = [line.strip()
+                                for line in html_source.splitlines(False)
+                                if line.strip()]
+                self.assertListEqual([html_doctype,
+                                      '<html xmlns:cubicweb="http://www.cubicweb.org" lang="cz">',
+                                      '<head>'],
+                                     source_lines[:3])
 
 if __name__ == '__main__':
     unittest_main()
--- a/web/test/unittest_views_editforms.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/test/unittest_views_editforms.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -15,9 +15,6 @@
 #
 # You should have received a copy of the GNU Lesser General Public License along
 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
-"""
-
-"""
 from logilab.common.testlib import unittest_main, mock_object
 
 from cubicweb.devtools.testlib import CubicWebTC
@@ -32,154 +29,171 @@
         permission = 'update'
     else:
         permission = 'add'
-    return [(rschema.type, x) for rschema, tschemas, x in AFS.relations_by_section(entity, formtype, section, permission)]
+    return [(rschema.type, x)
+            for rschema, tschemas, x in AFS.relations_by_section(entity,
+                                                                 formtype,
+                                                                 section,
+                                                                 permission)]
 
 class AutomaticEntityFormTC(CubicWebTC):
 
     def test_custom_widget(self):
-        AFFK.tag_subject_of(('CWUser', 'login', '*'),
-                            {'widget': AutoCompletionWidget(autocomplete_initfunc='get_logins')})
-        form = self.vreg['forms'].select('edition', self.request(),
-                                         entity=self.user())
-        field = form.field_by_name('login', 'subject')
-        self.assertIsInstance(field.widget, AutoCompletionWidget)
-        AFFK.del_rtag('CWUser', 'login', '*', 'subject')
+        with self.admin_access.web_request() as req:
+            AFFK.tag_subject_of(('CWUser', 'login', '*'),
+                                {'widget': AutoCompletionWidget(autocomplete_initfunc='get_logins')})
+            form = self.vreg['forms'].select('edition', req, entity=self.user(req))
+            field = form.field_by_name('login', 'subject')
+            self.assertIsInstance(field.widget, AutoCompletionWidget)
+            AFFK.del_rtag('CWUser', 'login', '*', 'subject')
 
 
     def test_cwuser_relations_by_category(self):
-        e = self.vreg['etypes'].etype_class('CWUser')(self.request())
-        # see custom configuration in views.cwuser
-        self.assertEqual(rbc(e, 'main', 'attributes'),
-                          [('login', 'subject'),
-                           ('upassword', 'subject'),
-                           ('firstname', 'subject'),
-                           ('surname', 'subject'),
-                           ('in_group', 'subject'),
-                           ])
-        self.assertListEqual(rbc(e, 'muledit', 'attributes'),
+        with self.admin_access.web_request() as req:
+            e = self.vreg['etypes'].etype_class('CWUser')(req)
+            # see custom configuration in views.cwuser
+            self.assertEqual(rbc(e, 'main', 'attributes'),
                               [('login', 'subject'),
                                ('upassword', 'subject'),
+                               ('firstname', 'subject'),
+                               ('surname', 'subject'),
                                ('in_group', 'subject'),
                                ])
-        self.assertListEqual(rbc(e, 'main', 'metadata'),
-                              [('last_login_time', 'subject'),
-                               ('cw_source', 'subject'),
-                               ('creation_date', 'subject'),
-                               ('cwuri', 'subject'),
-                               ('modification_date', 'subject'),
-                               ('created_by', 'subject'),
-                               ('owned_by', 'subject'),
-                               ('bookmarked_by', 'object'),
-                               ])
-        # XXX skip 'tags' relation here and in the hidden category because
-        # of some test interdependancy when pytest is launched on whole cw
-        # (appears here while expected in hidden
-        self.assertListEqual([x for x in rbc(e, 'main', 'relations')
-                               if x != ('tags', 'object')],
-                              [('connait', 'subject'),
-                               ('custom_workflow', 'subject'),
-                               ('primary_email', 'subject'),
-                               ('checked_by', 'object'),
-                               ])
-        self.assertListEqual(rbc(e, 'main', 'inlined'),
-                              [('use_email', 'subject'),
-                               ])
-        # owned_by is defined both as subject and object relations on CWUser
-        self.assertListEqual(sorted(x for x in rbc(e, 'main', 'hidden')
-                                     if x != ('tags', 'object')),
-                              sorted([('for_user', 'object'),
-                                      ('created_by', 'object'),
-                                      ('wf_info_for', 'object'),
-                                      ('owned_by', 'object'),
-                                      ]))
+            self.assertListEqual(rbc(e, 'muledit', 'attributes'),
+                                  [('login', 'subject'),
+                                   ('upassword', 'subject'),
+                                   ('in_group', 'subject'),
+                                   ])
+            self.assertListEqual(rbc(e, 'main', 'metadata'),
+                                  [('last_login_time', 'subject'),
+                                   ('cw_source', 'subject'),
+                                   ('creation_date', 'subject'),
+                                   ('cwuri', 'subject'),
+                                   ('modification_date', 'subject'),
+                                   ('created_by', 'subject'),
+                                   ('owned_by', 'subject'),
+                                   ('bookmarked_by', 'object'),
+                                   ])
+            # XXX skip 'tags' relation here and in the hidden category because
+            # of some test interdependancy when pytest is launched on whole cw
+            # (appears here while expected in hidden
+            self.assertListEqual([x for x in rbc(e, 'main', 'relations')
+                                   if x != ('tags', 'object')],
+                                  [('connait', 'subject'),
+                                   ('custom_workflow', 'subject'),
+                                   ('primary_email', 'subject'),
+                                   ('checked_by', 'object'),
+                                   ])
+            self.assertListEqual(rbc(e, 'main', 'inlined'),
+                                  [('use_email', 'subject'),
+                                   ])
+            # owned_by is defined both as subject and object relations on CWUser
+            self.assertListEqual(sorted(x for x in rbc(e, 'main', 'hidden')
+                                         if x != ('tags', 'object')),
+                                  sorted([('for_user', 'object'),
+                                          ('created_by', 'object'),
+                                          ('wf_info_for', 'object'),
+                                          ('owned_by', 'object'),
+                                          ]))
 
     def test_inlined_view(self):
-        self.assertTrue('main_inlined' in AFS.etype_get('CWUser', 'use_email', 'subject', 'EmailAddress'))
-        self.assertFalse('main_inlined' in AFS.etype_get('CWUser', 'primary_email', 'subject', 'EmailAddress'))
-        self.assertTrue('main_relations' in AFS.etype_get('CWUser', 'primary_email', 'subject', 'EmailAddress'))
+        self.assertIn('main_inlined',
+                      AFS.etype_get('CWUser', 'use_email', 'subject', 'EmailAddress'))
+        self.assertNotIn('main_inlined',
+                         AFS.etype_get('CWUser', 'primary_email', 'subject', 'EmailAddress'))
+        self.assertIn('main_relations',
+                      AFS.etype_get('CWUser', 'primary_email', 'subject', 'EmailAddress'))
 
     def test_personne_relations_by_category(self):
-        e = self.vreg['etypes'].etype_class('Personne')(self.request())
-        self.assertListEqual(rbc(e, 'main', 'attributes'),
-                              [('nom', 'subject'),
-                               ('prenom', 'subject'),
-                               ('sexe', 'subject'),
-                               ('promo', 'subject'),
-                               ('titre', 'subject'),
-                               ('ass', 'subject'),
-                               ('web', 'subject'),
-                               ('tel', 'subject'),
-                               ('fax', 'subject'),
-                               ('datenaiss', 'subject'),
-                               ('test', 'subject'),
-                               ('description', 'subject'),
-                               ('salary', 'subject'),
-                               ])
-        self.assertListEqual(rbc(e, 'muledit', 'attributes'),
-                              [('nom', 'subject'),
-                               ])
-        self.assertListEqual(rbc(e, 'main', 'metadata'),
-                              [('cw_source', 'subject'),
-                               ('creation_date', 'subject'),
-                               ('cwuri', 'subject'),
-                               ('modification_date', 'subject'),
-                               ('created_by', 'subject'),
-                               ('owned_by', 'subject'),
-                               ])
-        self.assertListEqual(rbc(e, 'main', 'relations'),
-                              [('travaille', 'subject'),
-                               ('manager', 'object'),
-                               ('connait', 'object'),
-                               ])
-        self.assertListEqual(rbc(e, 'main', 'hidden'),
-                              [])
+        with self.admin_access.web_request() as req:
+            e = self.vreg['etypes'].etype_class('Personne')(req)
+            self.assertListEqual(rbc(e, 'main', 'attributes'),
+                                  [('nom', 'subject'),
+                                   ('prenom', 'subject'),
+                                   ('sexe', 'subject'),
+                                   ('promo', 'subject'),
+                                   ('titre', 'subject'),
+                                   ('ass', 'subject'),
+                                   ('web', 'subject'),
+                                   ('tel', 'subject'),
+                                   ('fax', 'subject'),
+                                   ('datenaiss', 'subject'),
+                                   ('test', 'subject'),
+                                   ('description', 'subject'),
+                                   ('salary', 'subject'),
+                                   ])
+            self.assertListEqual(rbc(e, 'muledit', 'attributes'),
+                                  [('nom', 'subject'),
+                                   ])
+            self.assertListEqual(rbc(e, 'main', 'metadata'),
+                                  [('cw_source', 'subject'),
+                                   ('creation_date', 'subject'),
+                                   ('cwuri', 'subject'),
+                                   ('modification_date', 'subject'),
+                                   ('created_by', 'subject'),
+                                   ('owned_by', 'subject'),
+                                   ])
+            self.assertListEqual(rbc(e, 'main', 'relations'),
+                                  [('travaille', 'subject'),
+                                   ('manager', 'object'),
+                                   ('connait', 'object'),
+                                   ])
+            self.assertListEqual(rbc(e, 'main', 'hidden'),
+                                  [])
 
     def test_edition_form(self):
-        rset = self.execute('CWUser X LIMIT 1')
-        form = self.vreg['forms'].select('edition', rset.req, rset=rset,
-                                row=0, col=0)
-        # should be also selectable by specifying entity
-        self.vreg['forms'].select('edition', rset.req,
-                         entity=rset.get_entity(0, 0))
-        self.assertFalse(any(f for f in form.fields if f is None))
+        with self.admin_access.web_request() as req:
+            rset = req.execute('CWUser X LIMIT 1')
+            form = self.vreg['forms'].select('edition', req, rset=rset, row=0, col=0)
+            # should be also selectable by specifying entity
+            self.vreg['forms'].select('edition', req, entity=rset.get_entity(0, 0))
+            self.assertFalse(any(f for f in form.fields if f is None))
 
 
 class FormViewsTC(CubicWebTC):
+
     def test_delete_conf_formview(self):
-        rset = self.execute('CWGroup X')
-        self.view('deleteconf', rset, template=None).source
+        with self.admin_access.web_request() as req:
+            rset = req.execute('CWGroup X')
+            self.view('deleteconf', rset, template=None, req=req).source
 
     def test_automatic_edition_formview(self):
-        rset = self.execute('CWUser X')
-        self.view('edition', rset, row=0, template=None).source
+        with self.admin_access.web_request() as req:
+            rset = req.execute('CWUser X')
+            self.view('edition', rset, row=0, template=None, req=req).source
 
-    def test_automatic_edition_formview(self):
-        rset = self.execute('CWUser X')
-        self.view('copy', rset, row=0, template=None).source
+    def test_automatic_edition_copyformview(self):
+        with self.admin_access.web_request() as req:
+            rset = req.execute('CWUser X')
+            self.view('copy', rset, row=0, template=None, req=req).source
 
     def test_automatic_creation_formview(self):
-        self.view('creation', None, etype='CWUser', template=None).source
+        with self.admin_access.web_request() as req:
+            self.view('creation', None, etype='CWUser', template=None, req=req).source
 
     def test_automatic_muledit_formview(self):
-        rset = self.execute('CWUser X')
-        self.view('muledit', rset, template=None).source
+        with self.admin_access.web_request() as req:
+            rset = req.execute('CWUser X')
+            self.view('muledit', rset, template=None, req=req).source
 
     def test_automatic_reledit_formview(self):
-        rset = self.execute('CWUser X')
-        self.view('reledit', rset, row=0, rtype='login', template=None).source
+        with self.admin_access.web_request() as req:
+            rset = req.execute('CWUser X')
+            self.view('reledit', rset, row=0, rtype='login', template=None, req=req).source
 
     def test_automatic_inline_edit_formview(self):
-        geid = self.execute('CWGroup X LIMIT 1')[0][0]
-        rset = self.execute('CWUser X LIMIT 1')
-        self.view('inline-edition', rset, row=0, col=0, rtype='in_group',
-                  peid=geid, role='object', i18nctx='', pform=MOCKPFORM,
-                  template=None).source
+        with self.admin_access.web_request() as req:
+            geid = req.execute('CWGroup X LIMIT 1')[0][0]
+            rset = req.execute('CWUser X LIMIT 1')
+            self.view('inline-edition', rset, row=0, col=0, rtype='in_group',
+                      peid=geid, role='object', i18nctx='', pform=MOCKPFORM,
+                      template=None, req=req).source
 
     def test_automatic_inline_creation_formview(self):
-        geid = self.execute('CWGroup X LIMIT 1')[0][0]
-        self.view('inline-creation', None, etype='CWUser', rtype='in_group',
-                  peid=geid, petype='CWGroup', i18nctx='', role='object', pform=MOCKPFORM,
-                  template=None)
+        with self.admin_access.web_request() as req:
+            geid = req.execute('CWGroup X LIMIT 1')[0][0]
+            self.view('inline-creation', None, etype='CWUser', rtype='in_group',
+                      peid=geid, petype='CWGroup', i18nctx='', role='object', pform=MOCKPFORM,
+                      template=None, req=req)
 
 MOCKPFORM = mock_object(form_previous_values={}, form_valerror=None)
 
--- a/web/test/unittest_views_json.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/test/unittest_views_json.py	Fri Jul 18 17:35:25 2014 +0200
@@ -30,14 +30,14 @@
     def test_json_rsetexport(self):
         with self.admin_access.web_request() as req:
             rset = req.execute('Any GN,COUNT(X) GROUPBY GN ORDERBY GN WHERE X in_group G, G name GN')
-            data = self.view('jsonexport', rset)
+            data = self.view('jsonexport', rset, req=req)
             self.assertEqual(req.headers_out.getRawHeaders('content-type'), ['application/json'])
             self.assertListEqual(data, [["guests", 1], ["managers", 1]])
 
     def test_json_rsetexport_empty_rset(self):
         with self.admin_access.web_request() as req:
             rset = req.execute('Any X WHERE X is CWUser, X login "foobarbaz"')
-            data = self.view('jsonexport', rset)
+            data = self.view('jsonexport', rset, req=req)
             self.assertEqual(req.headers_out.getRawHeaders('content-type'), ['application/json'])
             self.assertListEqual(data, [])
 
@@ -65,7 +65,7 @@
     def test_json_ersetexport(self):
         with self.admin_access.web_request() as req:
             rset = req.execute('Any G ORDERBY GN WHERE G is CWGroup, G name GN')
-            data = self.view('ejsonexport', rset)
+            data = self.view('ejsonexport', rset, req=req)
             self.assertEqual(req.headers_out.getRawHeaders('content-type'), ['application/json'])
             self.assertEqual(data[0]['name'], 'guests')
             self.assertEqual(data[1]['name'], 'managers')
--- a/web/test/unittest_views_navigation.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/test/unittest_views_navigation.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -17,7 +17,7 @@
 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
 """cubicweb.web.views.navigation unit tests"""
 
-from logilab.common.testlib import unittest_main, mock_object
+from logilab.common.testlib import unittest_main
 
 from cubicweb.devtools.testlib import CubicWebTC
 from cubicweb.web.views.navigation import (PageNavigation, SortedNavigation,
@@ -29,123 +29,94 @@
 class NavigationTC(CubicWebTC):
 
     def test_navigation_selection_whatever(self):
-        req = self.request()
-        rset = self.execute('Any X,N WHERE X name N')
-        navcomp = self.vreg['components'].select('navigation', req, rset=rset)
-        self.assertIsInstance(navcomp, PageNavigation)
-        req.set_search_state('W:X:Y:Z')
-        navcomp = self.vreg['components'].select('navigation', req, rset=rset)
-        self.assertIsInstance(navcomp, PageNavigation)
-        req.set_search_state('normal')
+        with self.admin_access.web_request() as req:
+            rset = req.execute('Any X,N WHERE X name N')
+            navcomp = self.vreg['components'].select('navigation', req, rset=rset)
+            self.assertIsInstance(navcomp, PageNavigation)
+            req.set_search_state('W:X:Y:Z')
+            navcomp = self.vreg['components'].select('navigation', req, rset=rset)
+            self.assertIsInstance(navcomp, PageNavigation)
+            req.set_search_state('normal')
 
     def test_navigation_selection_ordered(self):
-        req = self.request()
-        rset = self.execute('Any X,N ORDERBY N LIMIT 40 WHERE X name N')
-        navcomp = self.vreg['components'].select('navigation', req, rset=rset, page_size=20)
-        self.assertIsInstance(navcomp, SortedNavigation)
-        req.set_search_state('W:X:Y:Z')
-        navcomp = self.vreg['components'].select('navigation', req, rset=rset, page_size=20)
-        self.assertIsInstance(navcomp, SortedNavigation)
-        req.set_search_state('normal')
-        html = navcomp.render()
+        with self.admin_access.web_request() as req:
+            rset = req.execute('Any X,N ORDERBY N LIMIT 40 WHERE X name N')
+            navcomp = self.vreg['components'].select('navigation', req, rset=rset, page_size=20)
+            self.assertIsInstance(navcomp, SortedNavigation)
+            req.set_search_state('W:X:Y:Z')
+            navcomp = self.vreg['components'].select('navigation', req, rset=rset, page_size=20)
+            self.assertIsInstance(navcomp, SortedNavigation)
+            req.set_search_state('normal')
+            navcomp.render()
 
     def test_navigation_selection_large_rset(self):
-        req = self.request()
-        rset = self.execute('Any X,N LIMIT 120 WHERE X name N')
-        navcomp = self.vreg['components'].select('navigation', req, rset=rset, page_size=20)
-        self.assertIsInstance(navcomp, PageNavigationSelect)
-        rset = self.execute('Any X,N ORDERBY N LIMIT 120 WHERE X name N')
-        navcomp = self.vreg['components'].select('navigation', req, rset=rset, page_size=20)
-        self.assertIsInstance(navcomp, PageNavigationSelect)
+        with self.admin_access.web_request() as req:
+            rset = req.execute('Any X,N LIMIT 120 WHERE X name N')
+            navcomp = self.vreg['components'].select('navigation', req, rset=rset, page_size=20)
+            self.assertIsInstance(navcomp, PageNavigationSelect)
+            rset = req.execute('Any X,N ORDERBY N LIMIT 120 WHERE X name N')
+            navcomp = self.vreg['components'].select('navigation', req, rset=rset, page_size=20)
+            self.assertIsInstance(navcomp, PageNavigationSelect)
 
     def test_navigation_selection_not_enough_1(self):
-        req = self.request()
-        rset = self.execute('Any X,N LIMIT 10 WHERE X name N')
-        navcomp = self.vreg['components'].select_or_none('navigation', req, rset=rset)
-        self.assertEqual(navcomp, None)
-        req.set_search_state('W:X:Y:Z')
-        navcomp = self.vreg['components'].select_or_none('navigation', req, rset=rset)
-        self.assertEqual(navcomp, None)
-        req.set_search_state('normal')
+        with self.admin_access.web_request() as req:
+            rset = req.execute('Any X,N LIMIT 10 WHERE X name N')
+            navcomp = self.vreg['components'].select_or_none('navigation', req, rset=rset)
+            self.assertEqual(navcomp, None)
+            req.set_search_state('W:X:Y:Z')
+            navcomp = self.vreg['components'].select_or_none('navigation', req, rset=rset)
+            self.assertEqual(navcomp, None)
+            req.set_search_state('normal')
 
     def test_navigation_selection_not_enough_2(self):
-        req = self.request()
-        rset = self.execute('Any N, COUNT(RDEF) GROUPBY N ORDERBY N WHERE RDEF relation_type RT, RT name N')
-        navcomp = self.vreg['components'].select('navigation', req, rset=rset)
-        self.assertIsInstance(navcomp, SortedNavigation)
-        req.set_search_state('W:X:Y:Z')
-        navcomp = self.vreg['components'].select('navigation', req, rset=rset)
-        self.assertIsInstance(navcomp, SortedNavigation)
+        with self.admin_access.web_request() as req:
+            rset = req.execute('Any N, COUNT(RDEF) GROUPBY N ORDERBY N '
+                               'WHERE RDEF relation_type RT, RT name N')
+            navcomp = self.vreg['components'].select('navigation', req, rset=rset)
+            self.assertIsInstance(navcomp, SortedNavigation)
+            req.set_search_state('W:X:Y:Z')
+            navcomp = self.vreg['components'].select('navigation', req, rset=rset)
+            self.assertIsInstance(navcomp, SortedNavigation)
 
     def test_navigation_selection_wrong_boundary(self):
-        req = self.request()
-        rset = self.execute('Any X,N WHERE X name N')
-        req = self.request()
-        req.form['__start'] = 1000000
-        navcomp = self.vreg['components'].select('navigation', req, rset=rset)
-        html = navcomp.render()
+        with self.admin_access.web_request() as req:
+            rset = req.execute('Any X,N WHERE X name N')
+            req.form['__start'] = 1000000
+            navcomp = self.vreg['components'].select('navigation', req, rset=rset)
+            html = navcomp.render()
 
     def test_sorted_navigation_1(self):
-        req = self.request()
-        rset = self.execute('Any RDEF ORDERBY RT WHERE RDEF relation_type RT')
-        navcomp = self.vreg['components'].select('navigation', req, rset=rset)
-        html = navcomp.render()
+        with self.admin_access.web_request() as req:
+            rset = req.execute('Any RDEF ORDERBY RT WHERE RDEF relation_type RT')
+            navcomp = self.vreg['components'].select('navigation', req, rset=rset)
+            html = navcomp.render()
 
     def test_sorted_navigation_2(self):
-        req = self.request()
-        rset = self.execute('Any RDEF ORDERBY RDEF WHERE RDEF relation_type RT')
-        navcomp = self.vreg['components'].select('navigation', req, rset=rset)
-        html = navcomp.render()
+        with self.admin_access.web_request() as req:
+            rset = req.execute('Any RDEF ORDERBY RDEF WHERE RDEF relation_type RT')
+            navcomp = self.vreg['components'].select('navigation', req, rset=rset)
+            html = navcomp.render()
 
     def test_sorted_navigation_3(self):
-        req = self.request()
-        rset = self.execute('CWAttribute RDEF ORDERBY RDEF')
-        navcomp = self.vreg['components'].select('navigation', req, rset=rset)
-        html = navcomp.render()
+        with self.admin_access.web_request() as req:
+            rset = req.execute('CWAttribute RDEF ORDERBY RDEF')
+            navcomp = self.vreg['components'].select('navigation', req, rset=rset)
+            html = navcomp.render()
 
     def test_sorted_navigation_4(self):
-        req = self.request()
-        rset = self.execute('Any RDEF ORDERBY N WHERE RDEF relation_type RT, RT name N')
-        navcomp = self.vreg['components'].select('navigation', req, rset=rset)
-        html = navcomp.render()
+        with self.admin_access.web_request() as req:
+            rset = req.execute('Any RDEF ORDERBY N '
+                               'WHERE RDEF relation_type RT, RT name N')
+            navcomp = self.vreg['components'].select('navigation', req, rset=rset)
+            html = navcomp.render()
 
     def test_sorted_navigation_5(self):
-        req = self.request()
-        rset = self.execute('Any N, COUNT(RDEF) GROUPBY N ORDERBY N WHERE RDEF relation_type RT, RT name N')
-        navcomp = self.vreg['components'].select('navigation', rset.req, rset=rset)
-        html = navcomp.render()
-
+        with self.admin_access.web_request() as req:
+            rset = req.execute('Any N, COUNT(RDEF) GROUPBY N ORDERBY N '
+                               'WHERE RDEF relation_type RT, RT name N')
+            navcomp = self.vreg['components'].select('navigation', rset.req, rset=rset)
+            html = navcomp.render()
 
-# XXX deactivate, contextual component has been removed
-# class ContentNavigationTC(CubicWebTC):
-    # def test_component_context(self):
-    #     view = mock_object(is_primary=lambda x: True)
-    #     rset = self.execute('CWUser X LIMIT 1')
-    #     req = self.request()
-    #     objs = self.vreg['ctxcomponents'].poss_visible_objects(
-    #         req, rset=rset, view=view, context='navtop')
-    #     # breadcrumbs should be in headers by default
-    #     clsids = set(obj.id for obj in objs)
-    #     self.assertIn('breadcrumbs', clsids)
-    #     objs = self.vreg['ctxcomponents'].poss_visible_objects(
-    #         req, rset=rset, view=view, context='navbottom')
-    #     # breadcrumbs should _NOT_ be in footers by default
-    #     clsids = set(obj.id for obj in objs)
-    #     self.assertNotIn('breadcrumbs', clsids)
-    #     self.execute('INSERT CWProperty P: P pkey "ctxcomponents.breadcrumbs.context", '
-    #                  'P value "navbottom"')
-    #     # breadcrumbs should now be in footers
-    #     req.cnx.commit()
-    #     objs = self.vreg['ctxcomponents'].poss_visible_objects(
-    #         req, rset=rset, view=view, context='navbottom')
-
-    #     clsids = [obj.id for obj in objs]
-    #     self.assertIn('breadcrumbs', clsids)
-    #     objs = self.vreg['ctxcomponents'].poss_visible_objects(
-    #         req, rset=rset, view=view, context='navtop')
-
-    #     clsids = [obj.id for obj in objs]
-    #     self.assertNotIn('breadcrumbs', clsids)
 
 
 if __name__ == '__main__':
--- a/web/test/unittest_views_xmlrss.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/test/unittest_views_xmlrss.py	Fri Jul 18 17:35:25 2014 +0200
@@ -10,7 +10,7 @@
             self.assertMultiLineEqual(
                 req.user.view('xml'),
                 '''\
-<CWUser eid="6" cwuri="None6" cwsource="system">
+<CWUser eid="6" cwuri="http://testing.fr/cubicweb/6" cwsource="system">
   <login>admin</login>
   <upassword/>
   <firstname/>
@@ -21,10 +21,10 @@
   <tags role="object">
   </tags>
   <in_group role="subject">
-    <CWGroup eid="%(group_eid)s" cwuri="None%(group_eid)s"/>
+    <CWGroup eid="%(group_eid)s" cwuri="http://testing.fr/cubicweb/%(group_eid)s"/>
   </in_group>
   <in_state role="subject">
-    <State eid="%(state_eid)s" cwuri="None%(state_eid)s" name="activated"/>
+    <State eid="%(state_eid)s" cwuri="http://testing.fr/cubicweb/%(state_eid)s" name="activated"/>
   </in_state>
   <use_email role="subject">
   </use_email>
--- a/web/test/unittest_web.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/test/unittest_web.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -18,6 +18,7 @@
 
 from json import loads
 from os.path import join
+import tempfile
 
 try:
     import requests
@@ -64,7 +65,8 @@
 
     @property
     def _post_url(self):
-        return self.request().build_url('ajax', fname='fileupload')
+        with self.admin_access.web_request() as req:
+            return req.build_url('ajax', fname='fileupload')
 
     def _fobject(self, fname):
         return open(join(self.datadir, fname), 'rb')
@@ -92,6 +94,7 @@
         self.assertEqual(webreq.status_code, 200)
         self.assertDictEqual(expect, loads(webreq.content))
 
+
 class LanguageTC(CubicWebServerTC):
 
     def test_language_neg(self):
@@ -115,5 +118,21 @@
         self.assertEqual(webreq.status, 200)
 
 
+class LogQueriesTC(CubicWebServerTC):
+    @classmethod
+    def init_config(cls, config):
+        super(LogQueriesTC, cls).init_config(config)
+        cls.logfile = tempfile.NamedTemporaryFile()
+        config.global_set_option('query-log-file', cls.logfile.name)
+
+    def test_log_queries(self):
+        self.web_request()
+        self.assertTrue(self.logfile.read())
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.logfile.close()
+
+
 if __name__ == '__main__':
     unittest_main()
--- a/web/views/ajaxedit.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/views/ajaxedit.py	Fri Jul 18 17:35:25 2014 +0200
@@ -53,9 +53,9 @@
         self.w(u'<h1>%s</h1>' % self._cw._('relation %(relname)s of %(ent)s')
                % {'relname': rschema.display_name(self._cw, role(self)),
                   'ent': entity.view('incontext')})
-        self.w(u'<ul>')
+        self.w(u'<ul class="list-unstyled">')
         for boxitem in self.unrelated_boxitems(entity):
-            self.w('<li class="invisible">%s</li>' % boxitem)
+            self.w('<li>%s</li>' % boxitem)
         self.w(u'</ul></div>')
 
     def unrelated_entities(self, entity):
--- a/web/views/authentication.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/views/authentication.py	Fri Jul 18 17:35:25 2014 +0200
@@ -44,7 +44,7 @@
         """
         raise NotImplementedError()
 
-    def authenticated(self, retriever, req, cnx, login, authinfo):
+    def authenticated(self, retriever, req, session, login, authinfo):
         """callback when return authentication information have opened a
         repository connection successfully. Take care req has no session
         attached yet, hence req.execute isn't available.
--- a/web/views/autoform.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/views/autoform.py	Fri Jul 18 17:35:25 2014 +0200
@@ -504,15 +504,15 @@
                 label = rschema.display_name(req, role, context=form.edited_entity.cw_etype)
                 w(u'<tr><th class="labelCol">%s</th>' % label)
                 w(u'<td>')
-                w(u'<ul>')
+                w(u'<ul class="list-unstyled">')
                 for viewparams in related:
-                    w(u'<li class="invisible">%s<span id="span%s" class="%s">%s</span></li>'
+                    w(u'<li>%s<span id="span%s" class="%s">%s</span></li>'
                       % (viewparams[1], viewparams[0], viewparams[2], viewparams[3]))
                 if not form.force_display and form.maxrelitems < len(related):
-                    link = (u'<span class="invisible">'
+                    link = (u'<span>'
                             '[<a href="javascript: window.location.href+=\'&amp;__force_display=1\'">%s</a>]'
                             '</span>' % _('view all'))
-                    w(u'<li class="invisible">%s</li>' % link)
+                    w(u'<li>%s</li>' % link)
                 w(u'</ul>')
                 w(u'</td>')
                 w(u'</tr>')
--- a/web/views/reledit.py	Thu Jul 17 11:08:56 2014 +0200
+++ b/web/views/reledit.py	Fri Jul 18 17:35:25 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -329,13 +329,13 @@
         w = self.w
         w(u'<div id="%(id)s-reledit" onmouseout="%(out)s" onmouseover="%(over)s" class="%(css)s">' %
           {'id': divid, 'css': 'releditField',
-           'out': "jQuery('#%s').addClass('hidden')" % divid,
-           'over': "jQuery('#%s').removeClass('hidden')" % divid})
+           'out': "jQuery('#%s').addClass('invisible')" % divid,
+           'over': "jQuery('#%s').removeClass('invisible')" % divid})
         w(u'<div id="%s-value" class="editableFieldValue">' % divid)
         w(value)
         w(u'</div>')
         form.render(w=w, renderer=renderer)
-        w(u'<div id="%s" class="editableField hidden">' % divid)
+        w(u'<div id="%s" class="editableField invisible">' % divid)
 
     def _edit_action(self, divid, args, edit_related, add_related, _delete_related):
         # XXX disambiguate wrt edit_related