merge 3.18.6 into 3.19
authorJulien Cristau <julien.cristau@logilab.fr>
Wed, 24 Sep 2014 18:04:30 +0200
changeset 9984 793377697c81
parent 9979 9ccdb3751fbe (current diff)
parent 9983 84738d495ffd (diff)
child 9985 c4e740e50fc7
merge 3.18.6 into 3.19
.hgtags
__init__.py
__pkginfo__.py
cubicweb.spec
cwctl.py
cwvreg.py
debian/changelog
debian/control
hooks/email.py
hooks/security.py
predicates.py
schema.py
server/querier.py
server/repository.py
server/serverctl.py
server/sources/native.py
server/test/data/migratedapp/schema.py
server/test/data/schema.py
server/test/unittest_querier.py
server/test/unittest_schemaserial.py
server/test/unittest_security.py
test/unittest_schema.py
web/_exceptions.py
web/facet.py
web/test/unittest_form.py
web/test/unittest_views_editforms.py
web/views/forms.py
web/views/uicfg.py
--- a/.hgtags	Fri Sep 12 09:49:01 2014 +0200
+++ b/.hgtags	Wed Sep 24 18:04:30 2014 +0200
@@ -335,6 +335,9 @@
 a979d1594af6501a774fb32eb67cd32fea626655 cubicweb-version-3.17.16
 a979d1594af6501a774fb32eb67cd32fea626655 cubicweb-debian-version-3.17.16-1
 a979d1594af6501a774fb32eb67cd32fea626655 cubicweb-centos-version-3.17.16-1
+57e9d1c70512d0f4e2c33d33db436a8274e10c1a cubicweb-version-3.17.17
+57e9d1c70512d0f4e2c33d33db436a8274e10c1a cubicweb-debian-version-3.17.17-1
+57e9d1c70512d0f4e2c33d33db436a8274e10c1a cubicweb-centos-version-3.17.17-1
 db37bf35a1474843ded0a537f9cb4838f4a78cda cubicweb-version-3.18.0
 db37bf35a1474843ded0a537f9cb4838f4a78cda cubicweb-debian-version-3.18.0-1
 db37bf35a1474843ded0a537f9cb4838f4a78cda cubicweb-centos-version-3.18.0-1
@@ -353,6 +356,9 @@
 5071b69b6b0b0de937bb231404cbf652a103dbe0 cubicweb-version-3.18.5
 5071b69b6b0b0de937bb231404cbf652a103dbe0 cubicweb-debian-version-3.18.5-1
 5071b69b6b0b0de937bb231404cbf652a103dbe0 cubicweb-centos-version-3.18.5-1
+d915013567429b481cb2c367071e36451c07a226 cubicweb-version-3.18.6
+d915013567429b481cb2c367071e36451c07a226 cubicweb-debian-version-3.18.6-1
+d915013567429b481cb2c367071e36451c07a226 cubicweb-centos-version-3.18.6-1
 1141927b8494aabd16e31b0d0d9a50fe1fed5f2f cubicweb-version-3.19.0
 1141927b8494aabd16e31b0d0d9a50fe1fed5f2f cubicweb-debian-version-3.19.0-1
 1141927b8494aabd16e31b0d0d9a50fe1fed5f2f cubicweb-centos-version-3.19.0-1
--- a/__init__.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/__init__.py	Wed Sep 24 18:04:30 2014 +0200
@@ -125,7 +125,7 @@
     def __eq__(self, other):
         if not isinstance(other, Binary):
             return False
-        return self.getvalue(), other.getvalue()
+        return self.getvalue() == other.getvalue()
 
 
     # Binary helpers to store/fetch python objects
--- a/__pkginfo__.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/__pkginfo__.py	Wed Sep 24 18:04:30 2014 +0200
@@ -39,7 +39,7 @@
 ]
 
 __depends__ = {
-    'logilab-common': '>= 0.60.0',
+    'logilab-common': '>= 0.62.0',
     'logilab-mtconverter': '>= 0.8.0',
     'rql': '>= 0.31.2',
     'yams': '>= 0.39.1',
--- a/cubicweb.spec	Fri Sep 12 09:49:01 2014 +0200
+++ b/cubicweb.spec	Wed Sep 24 18:04:30 2014 +0200
@@ -20,7 +20,7 @@
 BuildArch:      noarch
 
 Requires:       %{python}
-Requires:       %{python}-logilab-common >= 0.60.0
+Requires:       %{python}-logilab-common >= 0.62.0
 Requires:       %{python}-logilab-mtconverter >= 0.8.0
 Requires:       %{python}-rql >= 0.31.2
 Requires:       %{python}-yams >= 0.39.1
--- a/cwctl.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/cwctl.py	Wed Sep 24 18:04:30 2014 +0200
@@ -396,13 +396,14 @@
         print
         helper.bootstrap(cubes, self.config.automatic, self.config.config_level)
         # input for cubes specific options
-        sections = set(sect.lower() for sect, opt, odict in config.all_options()
-                       if 'type' in odict
-                       and odict.get('level') <= self.config.config_level)
-        for section in sections:
-            if section not in ('main', 'email', 'pyro', 'web'):
-                print '\n' + underline_title('%s options' % section)
-                config.input_config(section, self.config.config_level)
+        if not self.config.automatic:
+            sections = set(sect.lower() for sect, opt, odict in config.all_options()
+                           if 'type' in odict
+                           and odict.get('level') <= self.config.config_level)
+            for section in sections:
+                if section not in ('main', 'email', 'pyro', 'web'):
+                    print '\n' + underline_title('%s options' % section)
+                    config.input_config(section, self.config.config_level)
         # write down configuration
         config.save()
         self._handle_win32(config, appid)
--- a/cwvreg.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/cwvreg.py	Wed Sep 24 18:04:30 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.
@@ -241,7 +241,7 @@
 
 class CWRegistry(Registry):
     def __init__(self, vreg):
-        super(CWRegistry, self).__init__(vreg.config.debugmode)
+        super(CWRegistry, self).__init__(True)
         self.vreg = vreg
 
     @property
@@ -598,11 +598,33 @@
         if self.is_reload_needed(path):
             self.reload(path)
 
+    def _cleanup_sys_modules(self, path):
+        """Remove submodules of `directories` from `sys.modules` and cleanup
+        CW_EVENT_MANAGER accordingly.
+
+        We take care to properly remove obsolete registry callbacks.
+
+        """
+        caches = {}
+        callbackdata = CW_EVENT_MANAGER.callbacks.values()
+        for callbacklist in callbackdata:
+            for callback in callbacklist:
+                func = callback[0]
+                # for non-function callable, we do nothing interesting
+                module = getattr(func, '__module__', None)
+                caches[id(callback)] = module
+        deleted_modules = set(cleanup_sys_modules(path))
+        for callbacklist in callbackdata:
+            for callback in callbacklist[:]:
+                module = caches[id(callback)]
+                if module and module in deleted_modules:
+                    callbacklist.remove(callback)
+
     def reload(self, path, force_reload=True):
         """modification detected, reset and reload the vreg"""
         CW_EVENT_MANAGER.emit('before-registry-reload')
         if force_reload:
-            cleanup_sys_modules(path)
+            self._cleanup_sys_modules(path)
             cubes = self.config.cubes()
             # if the fs code use some cubes not yet registered into the instance
             # we should cleanup sys.modules for those as well to avoid potential
@@ -611,7 +633,7 @@
             for cube in cfg.expand_cubes(cubes, with_recommends=True):
                 if not cube in cubes:
                     cpath = cfg.build_appobjects_cube_path([cfg.cube_dir(cube)])
-                    cleanup_sys_modules(cpath)
+                    self._cleanup_sys_modules(cpath)
         self.register_objects(path)
         CW_EVENT_MANAGER.emit('after-registry-reload')
 
--- a/debian/changelog	Fri Sep 12 09:49:01 2014 +0200
+++ b/debian/changelog	Wed Sep 24 18:04:30 2014 +0200
@@ -22,6 +22,12 @@
 
  -- Julien Cristau <julien.cristau@logilab.fr>  Mon, 28 Apr 2014 18:35:27 +0200
 
+cubicweb (3.18.6-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Julien Cristau <julien.cristau@logilab.fr>  Wed, 24 Sep 2014 15:08:34 +0200
+
 cubicweb (3.18.5-1) unstable; urgency=low
 
   * new upstream release
@@ -58,9 +64,15 @@
 
  -- Julien Cristau <julien.cristau@logilab.fr>  Fri, 10 Jan 2014 17:14:18 +0100
 
+cubicweb (3.17.17-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Aurelien Campeas <aurelien.campeas@logilab.fr>  Tue, 16 Sep 2014 18:38:19 +0200
+
 cubicweb (3.17.16-1) unstable; urgency=low
 
-  * new upstream value
+  * new upstream release
 
  -- Aurelien Campeas <aurelien.campeas@logilab.fr>  Mon, 07 Jul 2014 19:26:12 +0200
 
--- a/debian/control	Fri Sep 12 09:49:01 2014 +0200
+++ b/debian/control	Wed Sep 24 18:04:30 2014 +0200
@@ -151,7 +151,7 @@
  graphviz,
  gettext,
  python-logilab-mtconverter (>= 0.8.0),
- python-logilab-common (>= 0.60.0),
+ python-logilab-common (>= 0.62.0),
  python-yams (>= 0.39.1),
  python-rql (>= 0.31.2),
  python-lxml
--- a/doc/book/en/devrepo/datamodel/definition.rst	Fri Sep 12 09:49:01 2014 +0200
+++ b/doc/book/en/devrepo/datamodel/definition.rst	Wed Sep 24 18:04:30 2014 +0200
@@ -300,7 +300,7 @@
 
 * users and groups of users
 * a user belongs to at least one group of user
-* permissions (read, update, create, delete)
+* permissions (`read`, `update`, `create`, `delete`)
 * permissions are assigned to groups (and not to users)
 
 For *CubicWeb* in particular:
@@ -320,10 +320,10 @@
   * the permissions of this group are only checked on `update`/`delete` actions
     if all the other groups the user belongs to do not provide those permissions
 
-Setting permissions is done with the attribute `__permissions__` of entities and
-relation definition. The value of this attribute is a dictionary where the keys
-are the access types (action), and the values are the authorized groups or
-expressions.
+Setting permissions is done with the class attribute `__permissions__`
+of entity types and relation definitions. The value of this attribute
+is a dictionary where the keys are the access types (action), and the
+values are the authorized groups or rql expressions.
 
 For an entity type, the possible actions are `read`, `add`, `update` and
 `delete`.
@@ -333,6 +333,19 @@
 For an attribute, the possible actions are `read`, `add` and `update`,
 and they are a refinement of an entity type permission.
 
+.. note::
+
+   By default, the permissions of an entity type attributes are
+   equivalent to the permissions of the entity type itself.
+
+   It is possible to provide custom attribute permissions which are
+   stronger than, or are more lenient than the entity type
+   permissions.
+
+   In a situation where all attributes were given custom permissions,
+   the entity type permissions would not be checked, except for the
+   `delete` action.
+
 For each access type, a tuple indicates the name of the authorized groups and/or
 one or multiple RQL expressions to satisfy to grant access. The access is
 provided if the user is in one of the listed groups or if one of the RQL condition
@@ -368,6 +381,13 @@
                       'add': ('managers', ERQLExpression('U has_add_permission X'),
                       'update': ('managers', ERQLExpression('U has_update_permission X')),}
 
+.. note::
+
+   The default permissions for attributes are not syntactically
+   equivalent to the default permissions of the entity types, but the
+   rql expressions work by delegating to the entity type permissions.
+
+
 The standard user groups
 ````````````````````````
 
@@ -670,7 +690,7 @@
   RelationType declaration which offers some advantages in the context
   of reusable cubes.
 
-  
+
 
 
 Handling schema changes
--- a/entities/wfobjs.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/entities/wfobjs.py	Wed Sep 24 18:04:30 2014 +0200
@@ -27,7 +27,6 @@
 
 from logilab.common.decorators import cached, clear_cache
 from logilab.common.deprecation import deprecated
-from logilab.common.compat import any
 
 from cubicweb.entities import AnyEntity, fetch_config
 from cubicweb.view import EntityAdapter
--- a/hooks/email.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/hooks/email.py	Wed Sep 24 18:04:30 2014 +0200
@@ -21,8 +21,6 @@
 
 from cubicweb.server import hook
 
-from logilab.common.compat import any
-
 
 class SetUseEmailRelationOp(hook.Operation):
     """delay this operation to commit to avoid conflict with a late rql query
--- a/hooks/security.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/hooks/security.py	Wed Sep 24 18:04:30 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.
@@ -34,11 +34,15 @@
 def check_entity_attributes(cnx, entity, action, editedattrs=None):
     eid = entity.eid
     eschema = entity.e_schema
+    if action == 'delete':
+        eschema.check_perm(session, action, eid=eid)
+        return
     # ._cw_skip_security_attributes is there to bypass security for attributes
     # set by hooks by modifying the entity's dictionary
     if editedattrs is None:
         editedattrs = entity.cw_edited
     dontcheck = editedattrs.skip_security
+    etypechecked = False
     for attr in editedattrs:
         if attr in dontcheck:
             continue
@@ -54,10 +58,10 @@
             # implements comparison by rql expression.
             if perms == buildobjs.DEFAULT_ATTRPERMS[action]:
                 # The default rule is to delegate to the entity
-                # rule. This is an historical artefact. Hence we take
-                # this object as a marker saying "no specific"
-                # permission rule for this attribute. Thus we just do
-                # nothing.
+                # rule. This needs to be checked only once.
+                if not etypechecked:
+                    entity.cw_check_perm(action)
+                    etypechecked = True
                 continue
             if perms == ():
                 # That means an immutable attribute; as an optimization, avoid
@@ -71,7 +75,6 @@
         cnx = self.cnx
         for eid, action, edited in self.get_data():
             entity = cnx.entity_from_eid(eid)
-            entity.cw_check_perm(action)
             check_entity_attributes(cnx, entity, action, edited)
 
 
--- a/predicates.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/predicates.py	Wed Sep 24 18:04:30 2014 +0200
@@ -188,7 +188,6 @@
 from warnings import warn
 from operator import eq
 
-from logilab.common.compat import all, any
 from logilab.common.interface import implements as implements_iface
 from logilab.common.registry import Predicate, objectify_predicate, yes
 
--- a/schema.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/schema.py	Wed Sep 24 18:04:30 2014 +0200
@@ -31,7 +31,6 @@
 from logilab.common.deprecation import deprecated, class_moved, moved
 from logilab.common.textutils import splitstrip
 from logilab.common.graph import get_cycles
-from logilab.common.compat import any
 
 from yams import BadSchemaDefinition, buildobjs as ybo
 from yams.schema import Schema, ERSchema, EntitySchema, RelationSchema, \
--- a/server/querier.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/server/querier.py	Wed Sep 24 18:04:30 2014 +0200
@@ -22,7 +22,6 @@
 
 from itertools import repeat
 
-from logilab.common.compat import any
 from rql import RQLSyntaxError, CoercionError
 from rql.stmts import Union
 from rql.nodes import ETYPE_PYOBJ_MAP, etype_from_pyobj, Relation, Exists, Not
--- a/server/rqlannotation.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/server/rqlannotation.py	Wed Sep 24 18:04:30 2014 +0200
@@ -21,8 +21,6 @@
 
 __docformat__ = "restructuredtext en"
 
-from logilab.common.compat import any
-
 from rql import BadRQLQuery
 from rql.nodes import Relation, VariableRef, Constant, Variable, Or, Exists
 from rql.utils import common_parent
--- a/server/serverctl.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/server/serverctl.py	Wed Sep 24 18:04:30 2014 +0200
@@ -423,7 +423,7 @@
           'question.',
           }),
         ('config-level',
-         {'short': 'l', 'type': 'int', 'default': 1,
+         {'short': 'l', 'type': 'int', 'default': 0,
           'help': 'level threshold for questions asked when configuring '
           'another source'
           }),
--- a/server/sources/native.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/server/sources/native.py	Wed Sep 24 18:04:30 2014 +0200
@@ -38,7 +38,6 @@
 import logging
 import sys
 
-from logilab.common.compat import any
 from logilab.common.decorators import cached, clear_cache
 from logilab.common.configuration import Method
 from logilab.common.shellutils import getlogin
--- a/server/test/data/migratedapp/schema.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/server/test/data/migratedapp/schema.py	Wed Sep 24 18:04:30 2014 +0200
@@ -91,6 +91,22 @@
     attachment = SubjectRelation('File')
 
 
+class Frozable(EntityType):
+    __permissions__ = {
+        'read':   ('managers', 'users'),
+        'add':    ('managers', 'users'),
+        'update': ('managers', ERQLExpression('X frozen False'),),
+        'delete': ('managers', ERQLExpression('X frozen False'),)
+    }
+    name = String()
+    frozen = Boolean(default=False,
+                     __permissions__ = {
+                         'read':   ('managers', 'users'),
+                         'add':    ('managers', 'users'),
+                         'update': ('managers', 'owners')
+                         })
+
+
 class Personne(EntityType):
     __unique_together__ = [('nom', 'prenom', 'datenaiss')]
     nom    = String(fulltextindexed=True, required=True, maxsize=64)
--- a/server/test/data/schema.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/server/test/data/schema.py	Wed Sep 24 18:04:30 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.
@@ -92,6 +92,7 @@
     type = String(maxsize=6)
     para = String(maxsize=512,
                   __permissions__ = {
+                      'add': ('managers', ERQLExpression('X in_state S, S name "todo"')),
                       'read':   ('managers', 'users', 'guests'),
                       'update': ('managers', ERQLExpression('X in_state S, S name "todo"')),
                       })
@@ -109,6 +110,23 @@
                                                                'S,Y')])
     todo_by = SubjectRelation('CWUser')
 
+
+class Frozable(EntityType):
+    __permissions__ = {
+        'read':   ('managers', 'users'),
+        'add':    ('managers', 'users'),
+        'update': ('managers', ERQLExpression('X frozen False'),),
+        'delete': ('managers', ERQLExpression('X frozen False'),)
+    }
+    name = String()
+    frozen = Boolean(default=False,
+                     __permissions__ = {
+                         'read':   ('managers', 'users'),
+                         'add':    ('managers', 'users'),
+                         'update': ('managers', 'owners')
+                         })
+
+
 class Personne(EntityType):
     __unique_together__ = [('nom', 'prenom', 'inline2')]
     nom    = String(fulltextindexed=True, required=True, maxsize=64)
--- a/server/test/unittest_querier.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/server/test/unittest_querier.py	Wed Sep 24 18:04:30 2014 +0200
@@ -176,8 +176,8 @@
                                 '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, '
+                                '        Division, Email, EmailPart, EmailThread, ExternalUri, File, Folder, Frozable, '
+                                '        Note, Old, Personne, RQLExpression, Societe, State, SubDivision, '
                                 '        SubWorkflowExitPoint, Tag, TrInfo, Transition, Workflow, WorkflowTransition)')
             self.assertListEqual(sorted(solutions),
                                   sorted([{'X': 'BaseTransition', 'ETN': 'String', 'ET': 'CWEType'},
@@ -204,6 +204,7 @@
                                           {'X': 'ExternalUri', 'ETN': 'String', 'ET': 'CWEType'},
                                           {'X': 'File', 'ETN': 'String', 'ET': 'CWEType'},
                                           {'X': 'Folder', 'ETN': 'String', 'ET': 'CWEType'},
+                                          {'X': 'Frozable', 'ETN': 'String', 'ET': 'CWEType'},
                                           {'X': 'Note', 'ETN': 'String', 'ET': 'CWEType'},
                                           {'X': 'Old', 'ETN': 'String', 'ET': 'CWEType'},
                                           {'X': 'Personne', 'ETN': 'String', 'ET': 'CWEType'},
@@ -604,16 +605,16 @@
         self.assertListEqual(rset.rows,
                               [[u'description_format', 12],
                                [u'description', 13],
-                               [u'name', 17],
-                               [u'created_by', 43],
-                               [u'creation_date', 43],
-                               [u'cw_source', 43],
-                               [u'cwuri', 43],
-                               [u'in_basket', 43],
-                               [u'is', 43],
-                               [u'is_instance_of', 43],
-                               [u'modification_date', 43],
-                               [u'owned_by', 43]])
+                               [u'name', 18],
+                               [u'created_by', 44],
+                               [u'creation_date', 44],
+                               [u'cw_source', 44],
+                               [u'cwuri', 44],
+                               [u'in_basket', 44],
+                               [u'is', 44],
+                               [u'is_instance_of', 44],
+                               [u'modification_date', 44],
+                               [u'owned_by', 44]])
 
     def test_select_aggregat_having_dumb(self):
         # dumb but should not raise an error
--- a/server/test/unittest_schemaserial.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/server/test/unittest_schemaserial.py	Wed Sep 24 18:04:30 2014 +0200
@@ -323,7 +323,7 @@
               'internationalizable': True,
               'fulltextindexed': False,
               'ordernum': 3,
-              'defaultval': Binary('text/plain'),
+              'defaultval': Binary.zpickle(u'text/plain'),
               'indexed': False,
               'cardinality': u'?1'}),
             ('INSERT CWConstraint X: X value %(value)s, X cstrtype CT, EDEF constrained_by X '
@@ -339,7 +339,6 @@
                              list(rdef2rql(schema['description_format'].rdefs[('CWRType', 'String')],
                                            cstrtypemap)))
 
-
     def test_updateeschema2rql1(self):
         self.assertListEqual([('SET X description %(description)s,X final %(final)s,'
                                'X name %(name)s WHERE X eid %(x)s',
--- a/server/test/unittest_security.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/server/test/unittest_security.py	Wed Sep 24 18:04:30 2014 +0200
@@ -408,6 +408,21 @@
             self.assertRaises(Unauthorized, cnx.commit)
             cnx.execute('SET X web "http://www.logilab.org" WHERE X eid %(x)s', {'x': eid})
             cnx.commit()
+        with self.new_access('iaminusersgrouponly').repo_cnx() as cnx:
+            cnx.execute('INSERT Frozable F: F name "Foo"')
+            cnx.commit()
+            cnx.execute('SET F name "Bar" WHERE F is Frozable')
+            cnx.commit()
+            cnx.execute('SET F name "BaBar" WHERE F is Frozable')
+            cnx.execute('SET F frozen True WHERE F is Frozable')
+            with self.assertRaises(Unauthorized):
+                cnx.commit()
+            cnx.rollback()
+            cnx.execute('SET F frozen True WHERE F is Frozable')
+            cnx.commit()
+            cnx.execute('SET F name "Bar" WHERE F is Frozable')
+            with self.assertRaises(Unauthorized):
+                cnx.commit()
 
     def test_attribute_security_rqlexpr(self):
         with self.admin_access.repo_cnx() as cnx:
--- a/test/unittest_schema.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/test/unittest_schema.py	Wed Sep 24 18:04:30 2014 +0200
@@ -188,7 +188,7 @@
                               'data', 'data_encoding', 'data_format', 'data_name', 'default_workflow', 'defaultval', 'delete_permission',
                               'description', 'description_format', 'destination_state', 'dirige',
 
-                              'ecrit_par', 'eid', 'end_timestamp', 'evaluee', 'expression', 'exprtype', 'extra_props',
+                              'ean', 'ecrit_par', 'eid', 'end_timestamp', 'evaluee', 'expression', 'exprtype', 'extra_props',
 
                               'fabrique_par', 'final', 'firstname', 'for_user', 'fournit',
                               'from_entity', 'from_state', 'fulltext_container', 'fulltextindexed',
--- a/toolsutils.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/toolsutils.py	Wed Sep 24 18:04:30 2014 +0200
@@ -33,7 +33,6 @@
         raise NotImplementedError
 
 from logilab.common.clcommands import Command as BaseCommand
-from logilab.common.compat import any
 from logilab.common.shellutils import ASK
 
 from cubicweb import warning # pylint: disable=E0611
--- a/uilib.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/uilib.py	Wed Sep 24 18:04:30 2014 +0200
@@ -444,12 +444,14 @@
 
 def exc_message(ex, encoding):
     try:
-        return unicode(ex)
+        excmsg = unicode(ex)
     except Exception:
         try:
-            return unicode(str(ex), encoding, 'replace')
+            excmsg = unicode(str(ex), encoding, 'replace')
         except Exception:
-            return unicode(repr(ex), encoding, 'replace')
+            excmsg = unicode(repr(ex), encoding, 'replace')
+    exctype = unicode(ex.__class__.__name__)
+    return u'%s: %s' % (exctype, excmsg)
 
 
 def rest_traceback(info, exception):
--- a/web/_exceptions.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/web/_exceptions.py	Wed Sep 24 18:04:30 2014 +0200
@@ -101,7 +101,7 @@
     """raised when a json remote call fails
     """
     def __init__(self, reason='', status=httplib.INTERNAL_SERVER_ERROR):
-        super(RemoteCallFailed, self).__init__(status=status)
+        super(RemoteCallFailed, self).__init__(reason, status=status)
         self.reason = reason
 
     def dumps(self):
--- a/web/data/cubicweb.form.css	Fri Sep 12 09:49:01 2014 +0200
+++ b/web/data/cubicweb.form.css	Wed Sep 24 18:04:30 2014 +0200
@@ -164,7 +164,7 @@
   font-weight: bold;
 }
  
-div.pendingDelete {
+.pendingDelete {
   text-decoration: line-through;
 }
 
--- a/web/facet.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/web/facet.py	Wed Sep 24 18:04:30 2014 +0200
@@ -61,7 +61,6 @@
 from logilab.common.graph import has_path
 from logilab.common.decorators import cached, cachedproperty
 from logilab.common.date import datetime2ticks, ustrftime, ticks2datetime
-from logilab.common.compat import all
 from logilab.common.deprecation import deprecated
 from logilab.common.registry import yes
 
@@ -1621,9 +1620,11 @@
             cssclass += ' hideFacetBody'
         w(u'<div class="%s" cubicweb:facetName="%s">%s</div>\n' %
                (cssclass, xml_escape(self.facet.__regid__), title))
+        w(u'<div class="facetBody">\n')
         w(u'<input name="%s" type="text" value="%s" />\n' % (
                 xml_escape(self.facet.__regid__), self.value or u''))
         w(u'</div>\n')
+        w(u'</div>\n')
 
 
 class FacetRangeWidget(htmlwidgets.HTMLWidget):
--- a/web/test/unittest_form.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/web/test/unittest_form.py	Wed Sep 24 18:04:30 2014 +0200
@@ -19,7 +19,6 @@
 from xml.etree.ElementTree import fromstring
 
 from logilab.common.testlib import unittest_main, mock_object
-from logilab.common.compat import any
 
 from cubicweb import Binary, ValidationError
 from cubicweb.devtools.testlib import CubicWebTC
--- a/web/views/forms.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/web/views/forms.py	Wed Sep 24 18:04:30 2014 +0200
@@ -47,7 +47,6 @@
 
 from logilab.common import dictattr, tempattr
 from logilab.common.decorators import iclassmethod, cached
-from logilab.common.compat import any
 from logilab.common.textutils import splitstrip
 from logilab.common.deprecation import deprecated
 
--- a/web/views/uicfg.py	Fri Sep 12 09:49:01 2014 +0200
+++ b/web/views/uicfg.py	Wed Sep 24 18:04:30 2014 +0200
@@ -57,8 +57,6 @@
 
 from warnings import warn
 
-from logilab.common.compat import any
-
 from cubicweb import neg_role
 from cubicweb.rtags import (RelationTags, RelationTagsBool, RelationTagsSet,
                             RelationTagsDict, NoTargetRelationTagsDict,