merge tls-sprint
authorsylvain.thenault@logilab.fr
Wed, 15 Apr 2009 17:30:03 +0200
branchtls-sprint
changeset 1373 5e6abf61636d
parent 1370 c1cf86a66e30 (diff)
parent 1372 d4264cd876e1 (current diff)
child 1380 aa1586de4563
merge
--- a/common/__init__.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/common/__init__.py	Wed Apr 15 17:30:03 2009 +0200
@@ -2,7 +2,7 @@
 hg stserver side and on the client side
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 
--- a/cwctl.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/cwctl.py	Wed Apr 15 17:30:03 2009 +0200
@@ -4,7 +4,7 @@
 %s"""
 
 import sys
-from os import remove, listdir, system, kill, getpgid
+from os import remove, listdir, system, kill, getpgid, pathsep
 from os.path import exists, join, isfile, isdir
 
 from logilab.common.clcommands import register_commands, pop_arg
@@ -176,7 +176,7 @@
                 print '   ', line
         print 
         try:
-            cubesdir = cwcfg.cubes_dir()
+            cubesdir = pathsep.join(cwcfg.cubes_search_path())
             namesize = max(len(x) for x in cwcfg.available_cubes())
         except ConfigurationError, ex:
             print 'No cubes available:', ex
--- a/cwvreg.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/cwvreg.py	Wed Apr 15 17:30:03 2009 +0200
@@ -122,11 +122,11 @@
                 return
             # remove vobjects that don't support any available interface
             implemented_interfaces = set()
-            for classes in self.get('etypes', {}).values():
-                for cls in classes:
-                    for iface in cls.__implements__:
-                        implemented_interfaces.update(iface.__mro__)
-                    implemented_interfaces.update(cls.__mro__)
+            for etype in self.schema.entities():
+                cls = self.etype_class(etype)
+                for iface in cls.__implements__:
+                    implemented_interfaces.update(iface.__mro__)
+                implemented_interfaces.update(cls.__mro__)
             for obj, ifaces in self._needs_iface.items():
                 ifaces = frozenset(isinstance(iface, basestring)
                                    and iface in self.schema
--- a/devtools/test/data/views/bug.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/devtools/test/data/views/bug.py	Wed Apr 15 17:30:03 2009 +0200
@@ -1,6 +1,7 @@
 """only for unit tests !"""
 
-from cubicweb.common.view import EntityView
+from cubicweb.view import EntityView
+from cubicweb.selectors import implements
 
 HTML_PAGE = u"""<html>
   <body>
@@ -11,7 +12,7 @@
 
 class SimpleView(EntityView):
     id = 'simple'
-    accepts = ('Bug',)
+    __select__ = implements('Bug',)
 
     def call(self, **kwargs):
         self.cell_call(0, 0)
@@ -21,7 +22,7 @@
 
 class RaisingView(EntityView):
     id = 'raising'
-    accepts = ('Bug',)
+    __select__ = implements('Bug',)
 
     def cell_call(self, row, col):
         raise ValueError()
--- a/entities/__init__.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/entities/__init__.py	Wed Apr 15 17:30:03 2009 +0200
@@ -306,7 +306,7 @@
         """
         if self.req.use_fckeditor() and self.e_schema.has_metadata(attr, 'format'):
             if self.has_eid() or '%s_format' % attr in self:
-                return self.attribute_metadata(attr, 'format') == 'text/html'
+                return self.attr_metadata(attr, 'format') == 'text/html'
             return self.req.property_value('ui.default-text-format') == 'text/html'
         return False
 
--- a/entities/authobjs.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/entities/authobjs.py	Wed Apr 15 17:30:03 2009 +0200
@@ -13,15 +13,16 @@
 class EGroup(AnyEntity):
     id = 'EGroup'
     fetch_attrs, fetch_order = fetch_config(['name'])
+    fetch_unrelated_order = fetch_order
 
     def db_key_name(self):
         """XXX goa specific"""
         return self.get('name')
-
     
 class EUser(AnyEntity):
     id = 'EUser'
     fetch_attrs, fetch_order = fetch_config(['login', 'firstname', 'surname'])
+    fetch_unrelated_order = fetch_order
     
     # used by repository to check if  the user can log in or not
     AUTHENTICABLE_STATES = ('activated',)
--- a/entities/test/unittest_base.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/entities/test/unittest_base.py	Wed Apr 15 17:30:03 2009 +0200
@@ -32,25 +32,6 @@
 
     def test_type(self):
         self.assertEquals(self.member.dc_type(), 'euser')
-
-    def test_custom_widget(self):
-        class EUser2(EUser):
-            widgets = {
-                'login' : 'AutoCompletionWidget',
-                }
-        clear_cache(self.vreg, 'etype_class')
-        self.vreg.register_vobject_class(EUser2)
-        p = self.entity('EUser U WHERE U login "member"')
-        self.failUnless(isinstance(p, EUser2))
-        w = p.get_widget('login')
-        self.failUnless(isinstance(w, AutoCompletionWidget))
-
-    def test_format_vocabulary(self):
-        card = self.add_entity('Card', title=u"hello")
-        self.assertEquals(card.default_content_format(), 'text/html')
-        self.execute('INSERT EProperty X: X pkey "ui.default-text-format", X value "text/rest", X for_user U WHERE U login "admin"')
-        self.commit()
-        self.assertEquals(card.default_content_format(), 'text/rest')
         
 
     def test_entity_meta_attributes(self):
@@ -258,20 +239,6 @@
         self.failUnless(e.matching_groups(('xyz', 'managers')))
         self.failIf(e.matching_groups(('xyz', 'abcd')))
 
-    def test_subject_in_state_vocabulary(self):
-        # on a new entity
-        e = self.etype_instance('EUser')
-        rschema = e.e_schema.subject_relation('in_state')
-        states = list(e.subject_in_state_vocabulary(rschema))
-        self.assertEquals(len(states), 1)
-        self.assertEquals(states[0][0], u'activated') # list of (combobox view, state eid)
-        # on an existant entity
-        e = self.entity('Any X WHERE X is EUser')
-        self.assertEquals(e.in_state[0].name, 'activated')
-        states = list(e.subject_in_state_vocabulary(rschema))
-        self.assertEquals(len(states), 1)
-        self.assertEquals(states[0][0], u'deactivated') # list of (combobox view, state eid)
-
     def test_workflow_base(self):
         e = self.create_user('toto')
         self.assertEquals(e.state, 'activated')
@@ -295,6 +262,7 @@
     def test_nonregr_subclasses_and_mixins_interfaces(self):
         class MyUser(EUser):
             __implements__ = (IMileStone,)
+        self.vreg._loadedmods[__name__] = {}
         self.vreg.register_vobject_class(MyUser)
         self.failUnless(implements(EUser, IWorkflowable))
         self.failUnless(implements(MyUser, IMileStone))
@@ -315,6 +283,7 @@
         #self.assertEquals(eclass.__bases__, (AnyEntity,))
         # build class from most generic to most specific and make
         # sure the most specific is always selected
+        self.vreg._loadedmods[__name__] = {}
         for etype in ('Company', 'Division', 'SubDivision'):
             class Foo(AnyEntity):
                 id = etype
--- a/entity.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/entity.py	Wed Apr 15 17:30:03 2009 +0200
@@ -278,9 +278,8 @@
         return selection, orderby, restrictions
 
     def __init__(self, req, rset, row=None, col=0):
-        AppRsetObject.__init__(self, req, rset)
+        AppRsetObject.__init__(self, req, rset, row, col)
         dict.__init__(self)
-        self.row, self.col = row, col
         self._related_cache = {}
         if rset is not None:
             self.eid = rset[row][col]
@@ -398,7 +397,7 @@
             needcheck = False
         return mainattr, needcheck
 
-    def attribute_metadata(self, attr, metadata):
+    def attr_metadata(self, attr, metadata):
         """return a metadata for an attribute (None if unspecified)"""
         value = getattr(self, '%s_%s' % (attr, metadata), None)
         if value is None and metadata == 'encoding':
@@ -425,14 +424,14 @@
             # description...
             if props.get('internationalizable'):
                 value = self.req._(value)
-            attrformat = self.attribute_metadata(attr, 'format')
+            attrformat = self.attr_metadata(attr, 'format')
             if attrformat:
                 return self.mtc_transform(value, attrformat, format,
                                           self.req.encoding)
         elif attrtype == 'Bytes':
-            attrformat = self.attribute_metadata(attr, 'format')
+            attrformat = self.attr_metadata(attr, 'format')
             if attrformat:
-                encoding = self.attribute_metadata(attr, 'encoding')
+                encoding = self.attr_metadata(attr, 'encoding')
                 return self.mtc_transform(value.getvalue(), attrformat, format,
                                           encoding)
             return u''
--- a/rtags.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/rtags.py	Wed Apr 15 17:30:03 2009 +0200
@@ -27,6 +27,11 @@
         assert role in ('subject', 'object'), role
         self._tagdefs[(str(rtype), role, str(stype), str(otype))] = tag
         
+    def del_rtag(self, rtype, role, stype='*', otype='*'):
+        assert not self.use_set
+        assert role in ('subject', 'object'), role
+        del self._tagdefs[(str(rtype), role, str(stype), str(otype))]
+        
     def rtag(self, rtype, role, stype='*', otype='*'):
         assert not self.use_set
         for key in reversed(self._get_keys(rtype, role, stype, otype)):
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/data/cubes/file/__pkginfo__.py	Wed Apr 15 17:30:03 2009 +0200
@@ -0,0 +1,54 @@
+# pylint: disable-msg=W0622
+"""cubicweb-file packaging information"""
+
+distname = "cubicweb-file"
+modname = distname.split('-', 1)[1]
+
+numversion = (1, 4, 3)
+version = '.'.join(str(num) for num in numversion)
+
+license = 'LGPL'
+copyright = '''Copyright (c) 2003-2009 LOGILAB S.A. (Paris, FRANCE).
+http://www.logilab.fr/ -- mailto:contact@logilab.fr'''
+
+author = "Logilab"
+author_email = "contact@logilab.fr"
+web = ''
+
+short_desc = "Raw file support for the CubicWeb framework"
+long_desc = """CubicWeb is a entities / relations bases knowledge management system
+developped at Logilab.
+.
+This package provides schema and views to store files and images in cubicweb
+applications.
+.
+"""
+
+from os import listdir
+from os.path import join
+
+CUBES_DIR = join('share', 'cubicweb', 'cubes')
+try:
+    data_files = [
+        [join(CUBES_DIR, 'file'),
+         [fname for fname in listdir('.')
+          if fname.endswith('.py') and fname != 'setup.py']],
+        [join(CUBES_DIR, 'file', 'data'),
+         [join('data', fname) for fname in listdir('data')]],
+        [join(CUBES_DIR, 'file', 'wdoc'),
+         [join('wdoc', fname) for fname in listdir('wdoc')]],
+        [join(CUBES_DIR, 'file', 'views'),
+         [join('views', fname) for fname in listdir('views') if fname.endswith('.py')]],
+        [join(CUBES_DIR, 'file', 'i18n'),
+         [join('i18n', fname) for fname in listdir('i18n')]],
+        [join(CUBES_DIR, 'file', 'migration'),
+         [join('migration', fname) for fname in listdir('migration')]],
+        ]
+except OSError:
+    # we are in an installed directory
+    pass
+
+
+cube_eid = 20320
+# used packages
+__use__ = ()
--- a/test/unittest_cwconfig.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/test/unittest_cwconfig.py	Wed Apr 15 17:30:03 2009 +0200
@@ -11,7 +11,7 @@
 def unabsolutize(path):
     parts = path.split(os.sep)
     for i, part in reversed(tuple(enumerate(parts))):
-        if part in ('cubicweb', 'cubes', 'cubes'):
+        if part.startswith('cubicweb') or part == 'cubes':
             return '/'.join(parts[i+1:])
     raise Exception('duh? %s' % path)
     
@@ -20,6 +20,9 @@
         self.config = ApptestConfiguration('data')
         self.config._cubes = ('email', 'file')
 
+    def tearDown(self):
+        os.environ.pop('CW_CUBES_PATH', None)
+
     def test_reorder_cubes(self):
         # jpl depends on email and file and comment
         # email depends on file
--- a/test/unittest_entity.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/test/unittest_entity.py	Wed Apr 15 17:30:03 2009 +0200
@@ -183,28 +183,25 @@
     def test_entity_unrelated(self):
         p = self.add_entity('Personne', nom=u'di mascio', prenom=u'adrien')
         e = self.add_entity('Tag', name=u'x')
-        rschema = e.e_schema.subject_relation('tags')
         related = [r.eid for r in e.tags]
         self.failUnlessEqual(related, [])
-        unrelated = [reid for rview, reid in e.vocabulary(rschema, 'subject')]
+        unrelated = [r[0] for r in e.unrelated('tags', 'Personne', 'subject')]
         self.failUnless(p.eid in unrelated)
         self.execute('SET X tags Y WHERE X is Tag, Y is Personne')
         e = self.entity('Any X WHERE X is Tag')
-        unrelated = [reid for rview, reid in e.vocabulary(rschema, 'subject')]
+        unrelated = [r[0] for r in e.unrelated('tags', 'Personne', 'subject')]
         self.failIf(p.eid in unrelated)
 
     def test_entity_unrelated_limit(self):
         e = self.add_entity('Tag', name=u'x')
         self.add_entity('Personne', nom=u'di mascio', prenom=u'adrien')
         self.add_entity('Personne', nom=u'di mascio', prenom=u'gwen')
-        rschema = e.e_schema.subject_relation('tags')
-        self.assertEquals(len(e.unrelated(rschema, 'Personne', 'subject', limit=1)),
+        self.assertEquals(len(e.unrelated('tags', 'Personne', 'subject', limit=1)),
                           1)
         
     def test_new_entity_unrelated(self):
         e = self.etype_instance('EUser')
-        rschema = e.e_schema.subject_relation('in_group')
-        unrelated = [reid for rview, reid in e.vocabulary(rschema, 'subject')]
+        unrelated = [r[0] for r in e.unrelated('in_group', 'EGroup', 'subject')]
         # should be default groups but owners, i.e. managers, users, guests
         self.assertEquals(len(unrelated), 3)
 
--- a/test/unittest_vregistry.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/test/unittest_vregistry.py	Wed Apr 15 17:30:03 2009 +0200
@@ -12,6 +12,8 @@
 class YesSchema:
     def __contains__(self, something):
         return True
+
+WEBVIEWSDIR = join(BASE, 'web', 'views')
     
 class VRegistryTC(TestCase):
 
@@ -20,10 +22,11 @@
         self.vreg = CubicWebRegistry(config)
         config.bootstrap_cubes()
         self.vreg.schema = config.load_schema()
-
+        
     def test_load(self):
-        self.vreg.load_file(join(BASE, 'web', 'views'), 'euser.py')
-        self.vreg.load_file(join(BASE, 'web', 'views'), 'baseviews.py')
+        self.vreg.init_registration([WEBVIEWSDIR])
+        self.vreg.load_file(join(WEBVIEWSDIR, 'euser.py'), 'cubicweb.web.views.euser')
+        self.vreg.load_file(join(WEBVIEWSDIR, 'baseviews.py'), 'cubicweb.web.views.baseviews')
         fpvc = [v for v in self.vreg.registry_objects('views', 'primary')
                if v.__module__ == 'cubicweb.web.views.euser'][0]
         fpv = fpvc(None, None)
@@ -31,8 +34,9 @@
         self.assertRaises(AttributeError, fpv.render_entity_attributes, None, None)
 
     def test_load_interface_based_vojects(self):
-        self.vreg.load_file(join(BASE, 'web', 'views'), 'idownloadable.py')
-        self.vreg.load_file(join(BASE, 'web', 'views'), 'baseviews.py')
+        self.vreg.init_registration([WEBVIEWSDIR])
+        self.vreg.load_file(join(WEBVIEWSDIR, 'idownloadable.py'), 'cubicweb.web.views.idownloadable')
+        self.vreg.load_file(join(WEBVIEWSDIR, 'baseviews.py'), 'cubicweb.web.views.baseviews')
         # check loading baseviews after idownloadable isn't kicking interface based views
         self.assertEquals(len(self.vreg['views']['primary']), 2)
                               
@@ -57,6 +61,7 @@
         class MyCard(Card):
             __implements__ = (IMileStone,)
         self.vreg.reset()
+        self.vreg._loadedmods[__name__] = {}
         self.vreg.register_vobject_class(MyCard)
         self.vreg.register_objects([join(BASE, 'web', 'views', 'iprogress.py')])
         # check progressbar isn't kicked
--- a/web/form.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/web/form.py	Wed Apr 15 17:30:03 2009 +0200
@@ -388,7 +388,7 @@
         msg = kwargs.pop('submitmsg', None)
         super(EntityFieldsForm, self).__init__(*args, **kwargs)
         if self.edited_entity is None:
-            self.edited_entity = self.complete_entity(self.row)
+            self.edited_entity = self.complete_entity(self.row, self.col)
         self.form_add_hidden('__type', eidparam=True)
         self.form_add_hidden('eid')
         if msg is not None:
@@ -486,14 +486,14 @@
         entity = self.edited_entity
         if field.eidparam and entity.e_schema.has_metadata(field.name, 'format') and (
             entity.has_eid() or '%s_format' % field.name in entity):
-            return self.edited_entity.attribute_metadata(field.name, 'format')
+            return self.edited_entity.attr_metadata(field.name, 'format')
         return self.req.property_value('ui.default-text-format')
 
     def form_field_encoding(self, field):
         entity = self.edited_entity
         if field.eidparam and entity.e_schema.has_metadata(field.name, 'encoding') and (
             entity.has_eid() or '%s_encoding' % field.name in entity):
-            return self.edited_entity.attribute_metadata(field.name, 'encoding')
+            return self.edited_entity.attr_metadata(field.name, 'encoding')
         return super(EntityFieldsForm, self).form_field_encoding(field)
     
     def form_field_error(self, field):
--- a/web/formrenderers.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/web/formrenderers.py	Wed Apr 15 17:30:03 2009 +0200
@@ -20,24 +20,35 @@
 class FormRenderer(object):
     """basic renderer displaying fields in a two columns table label | value
     """
+    display_fields = None # None -> all fields
+    display_label = True
+    display_help = True
+    display_progress_div = True
     button_bar_class = u'formButtonBar'
     
-    def __init__(self, display_fields=None, display_label=True,
-                 display_help=True, button_bar_class=None):
-        self.display_fields = display_fields # None -> all fields
-        self.display_label = display_label
-        self.display_help = display_help
-        if button_bar_class is not None:
-            self.button_bar_class = button_bar_class
-            
+    def __init__(self, **kwargs):
+        if self._set_options(kwargs):
+            raise ValueError('unconsumed arguments %s' % kwargs)
+
+    def _set_options(self, kwargs):
+        for key in ('display_fields', 'display_label', 'display_help',
+                    'display_progress_div', 'button_bar_class'):
+            try:
+                setattr(self, key, kwargs.pop(key))
+            except KeyError:
+                continue
+        return kwargs
+    
     # renderer interface ######################################################
     
     def render(self, form, values):
+        self._set_options(values)
         form.add_media()
         data = []
         w = data.append
         w(self.open_form(form, values))
-        w(u'<div id="progress">%s</div>' % form.req._('validating...'))
+        if self.display_progress_div:
+            w(u'<div id="progress">%s</div>' % form.req._('validating...'))
         w(u'<fieldset>')
         w(tags.input(type=u'hidden', name=u'__form_id',
                      value=values.get('formvid', form.id)))
--- a/web/formwidgets.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/web/formwidgets.py	Wed Apr 15 17:30:03 2009 +0200
@@ -203,19 +203,19 @@
     input will be generated for each possible value.
     """ 
     type = 'radio'
-    setdomid = False # by default, don't set id attribute on radio input
     
     def render(self, form, field):
         name, curvalues, attrs = self._render_attrs(form, field)
+        domid = attrs.pop('id', None)
         options = []
-        for label, value in field.vocabulary(form):
+        for i, (label, value) in enumerate(field.vocabulary(form)):
+            iattrs = attrs.copy()
+            if i == 0 and domid is not None:
+                iattrs['id'] = domid
             if value in curvalues:
-                tag = tags.input(name=name, type=self.type, value=value,
-                                 checked='checked', **attrs)
-            else:
-                tag = tags.input(name=name, type=self.type, value=value, **attrs)
-            tag += label + '<br/>'
-            options.append(tag)
+                iattrs['checked'] = u'checked'
+            tag = tags.input(name=name, type=self.type, value=value, **iattrs)
+            options.append(tag + label + '<br/>')
         return '\n'.join(options)
 
 
@@ -269,11 +269,11 @@
 
 def init_ajax_attributes(attrs, wdgtype, loadtype=u'auto'):
     try:
-        attrs[u'klass'] += u' widget'
+        attrs['klass'] += u' widget'
     except KeyError:
-        attrs[u'klass'] = u'widget'
-    attrs.setdefault(u'cubicweb:wdgtype', wdgtype)
-    attrs.setdefault(u'cubicweb:loadtype', loadtype)
+        attrs['klass'] = u'widget'
+    attrs.setdefault('cubicweb:wdgtype', wdgtype)
+    attrs.setdefault('cubicweb:loadtype', loadtype)
 
 
 class AjaxWidget(FieldWidget):
@@ -282,7 +282,7 @@
         super(AjaxWidget, self).__init__(**kwargs)
         init_ajax_attributes(self.attrs, wdgtype)
         if inputid is not None:
-            self.attrs[u'cubicweb:inputid'] = inputid
+            self.attrs['cubicweb:inputid'] = inputid
             
     def render(self, form, field):
         self.add_media(form)
@@ -342,7 +342,7 @@
   <input type="text" id="newopt" />
   <a href="javascript:noop()" id="add_newopt">&nbsp;</a></div>
 '''
-        
+
 # buttons ######################################################################
 
 class Button(Input):
--- a/web/test/test_views.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/web/test/test_views.py	Wed Apr 15 17:30:03 2009 +0200
@@ -45,6 +45,7 @@
         self.failUnless('jquery.tablesorter.js' in self.view('table', rset))
 
     def test_js_added_only_once(self):
+        self.vreg._loadedmods[__name__] = {}
         self.vreg.register_vobject_class(SomeView)
         rset = self.execute('EUser X')
         source = self.view('someview', rset).source
--- a/web/test/unittest_form.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/web/test/unittest_form.py	Wed Apr 15 17:30:03 2009 +0200
@@ -1,7 +1,7 @@
 from logilab.common.testlib import unittest_main, mock_object
 from cubicweb import Binary
 from cubicweb.devtools.testlib import WebTest
-from cubicweb.web.form import EntityFieldsForm, FormRenderer
+from cubicweb.web.form import EntityFieldsForm, FieldsForm, FormRenderer
 from cubicweb.web.formfields import (IntField, StringField, RichTextField,
                                      DateTimeField, DateTimePicker,
                                      FileField, EditableFileField)
@@ -9,6 +9,16 @@
 from cubicweb.web.views.workflow import ChangeStateForm
 
 
+class FieldsFormTC(WebTest):
+
+    def test_form_field_format(self):
+        form = FieldsForm(self.request(), None)
+        self.assertEquals(form.form_field_format(None), 'text/html')
+        self.execute('INSERT EProperty X: X pkey "ui.default-text-format", X value "text/rest", X for_user U WHERE U login "admin"')
+        self.commit()
+        self.assertEquals(form.form_field_format(None), 'text/rest')
+
+
 class EntityFieldsFormTC(WebTest):
 
     def setUp(self):
@@ -17,6 +27,44 @@
         self.entity = self.user(self.req)
         self.renderer = FormRenderer()
         
+    def test_form_field_vocabulary_unrelated(self):
+        b = self.add_entity('BlogEntry', title=u'di mascii code', content=u'a best-seller')
+        t = self.add_entity('Tag', name=u'x')
+        form1 = EntityFieldsForm(self.request(), None, entity=t)
+        unrelated = [reid for rview, reid in form1.subject_relation_vocabulary('tags')]
+        self.failUnless(b.eid in unrelated, unrelated)
+        form2 = EntityFieldsForm(self.request(), None, entity=b)
+        unrelated = [reid for rview, reid in form2.object_relation_vocabulary('tags')]
+        self.failUnless(t.eid in unrelated, unrelated)
+        self.execute('SET X tags Y WHERE X is Tag, Y is BlogEntry')
+        unrelated = [reid for rview, reid in form1.subject_relation_vocabulary('tags')]
+        self.failIf(b.eid in unrelated, unrelated)
+        unrelated = [reid for rview, reid in form2.object_relation_vocabulary('tags')]
+        self.failIf(t.eid in unrelated, unrelated)
+        
+    def test_form_field_vocabulary_new_entity(self):
+        e = self.etype_instance('EUser')
+        form = EntityFieldsForm(self.request(), None, entity=e)
+        unrelated = [rview for rview, reid in form.subject_relation_vocabulary('in_group')]
+        # should be default groups but owners, i.e. managers, users, guests
+        self.assertEquals(unrelated, [u'guests', u'managers', u'users'])
+
+    def test_subject_in_state_vocabulary(self):
+        # on a new entity
+        e = self.etype_instance('EUser')
+        form = EntityFieldsForm(self.request(), None, entity=e)
+        states = list(form.subject_in_state_vocabulary('in_state'))
+        self.assertEquals(len(states), 1)
+        self.assertEquals(states[0][0], u'activated') # list of (combobox view, state eid)
+        # on an existant entity
+        e = self.user()
+        form = EntityFieldsForm(self.request(), None, entity=e)
+        states = list(form.subject_in_state_vocabulary('in_state'))
+        self.assertEquals(len(states), 1)
+        self.assertEquals(states[0][0], u'deactivated') # list of (combobox view, state eid)
+
+
+        
     # form view tests #########################################################
         
     def test_massmailing_formview(self):
--- a/web/test/unittest_views_editforms.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/web/test/unittest_views_editforms.py	Wed Apr 15 17:30:03 2009 +0200
@@ -2,12 +2,21 @@
 from cubicweb.devtools.apptest import EnvBasedTC
 from cubicweb.devtools.testlib import WebTest
 from cubicweb.web.views.editforms import AutomaticEntityForm as AEF
-
+from cubicweb.web.formwidgets import AutoCompletionWidget
 def rbc(entity, category):
     return [(rschema.type, x) for rschema, tschemas, x in AEF.erelations_by_category(entity, category)]
 
 class AutomaticEntityFormTC(EnvBasedTC):
 
+    def test_custom_widget(self):
+        AEF.rwidgets.set_rtag(AutoCompletionWidget, 'login', 'subject', 'EUser')
+        form = self.vreg.select_object('forms', 'edition', self.request(), None,
+                                       entity=self.user())
+        field = form.field_by_name('login')
+        self.assertIsInstance(field.widget, AutoCompletionWidget)
+        AEF.rwidgets.del_rtag('login', 'subject', 'EUser')
+        
+
     def test_euser_relations_by_category(self):
         #for (rtype, role, stype, otype), tag in AEF.rcategories._tagdefs.items():
         #    if rtype == 'tags':
--- a/web/views/editcontroller.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/web/views/editcontroller.py	Wed Apr 15 17:30:03 2009 +0200
@@ -205,19 +205,23 @@
             # submitted, since it will think the attribute is not modified
             elif isinstance(value, unicode):
                 # file modified using a text widget
-                value = Binary(value.encode(entity.attribute_metadata(attr, 'encoding')))
+                encoding = entity.attr_metadata(attr, 'encoding')
+                value = Binary(value.encode(encoding))
             else:
-                # (filename, mimetype, stream)
+                # value is a  3-uple (filename, mimetype, stream)
                 val = Binary(value[2].read())
                 if not val.getvalue(): # usually an unexistant file
                     value = None
                 else:
                     val.filename = value[0]
-                    if entity.e_schema.has_metadata(attr, 'format'):
-                        key = '%s_format' % attr
-                        formparams[key] = value[1]
-                        self.relations.append('X %s_format %%(%s)s'
-                                              % (attr, key))
+                    # ignore browser submitted MIME type since it may be buggy
+                    # XXX add a config option to tell if we should consider it
+                    # or not?
+                    #if entity.e_schema.has_metadata(attr, 'format'):
+                    #    key = '%s_format' % attr
+                    #    formparams[key] = value[1]
+                    #    self.relations.append('X %s_format %%(%s)s'
+                    #                          % (attr, key))
                     # XXX suppose a File compatible schema
                     if entity.e_schema.has_subject_relation('name') \
                            and not formparams.get('name'):
--- a/web/views/editforms.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/web/views/editforms.py	Wed Apr 15 17:30:03 2009 +0200
@@ -118,7 +118,8 @@
                                        cssstyle='display: none',
                                        onsubmit=self.onsubmit % locals())
         renderer = FormRenderer(display_label=False, display_help=False,
-                                display_fields=(rtype,), button_bar_class='buttonbar')
+                                display_fields=(rtype,), button_bar_class='buttonbar',
+                                display_progress_div=False)
         self.w(tags.div(value, klass='editableField', id=divid,
                         ondblclick=self.ondblclick % locals()))
         self.w(form.form_render(renderer=renderer))
--- a/web/views/eproperties.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/web/views/eproperties.py	Wed Apr 15 17:30:03 2009 +0200
@@ -108,6 +108,8 @@
         req = self.req
         _ = req._
         w(u'<h1>%s</h1>\n' % _(self.title))
+        # we don't want this in each sub-forms
+        w(u'<div id="progress">%s</div>' % self.req._('validating...'))
         for label, group, form in sorted((_(g), g, f)
                                          for g, f in mainopts.iteritems()):
             status = css_class(self._group_status(group)) 
@@ -173,7 +175,7 @@
         form.form_add_hidden('__redirectpath', path)
         for key in keys:            
             self.form_row(form, key, splitlabel)
-        return form.form_render()
+        return form.form_render(display_progress_div=False)
 
     def form_row(self, form, key, splitlabel):
         entity = self.entity_for_key(key)
--- a/web/views/tableview.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/web/views/tableview.py	Wed Apr 15 17:30:03 2009 +0200
@@ -326,4 +326,3 @@
 class EditableInitialTableTableView(InitialTableView):
     id = 'editable-initialtable'
     finalview = 'editable-final'
-    
--- a/web/views/wdoc.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/web/views/wdoc.py	Wed Apr 15 17:30:03 2009 +0200
@@ -16,7 +16,7 @@
 
 from cubicweb.selectors import match_form_params
 from cubicweb.view import StartupView
-from cubicweb.utils import strptime
+from cubicweb.utils import strptime, todate
 from cubicweb.common.uilib import rest_publish
 from cubicweb.web import NotFound
 
@@ -192,6 +192,7 @@
         title = self.req._(self.title)
         restdata = ['.. -*- coding: utf-8 -*-', '', title, '='*len(title), '']
         w = restdata.append
+        today = date.today()
         for fpath in self.config.locate_all_files(rid):
             cl = ChangeLog(fpath)
             encoding = 'utf-8'
@@ -205,9 +206,9 @@
                     w(unicode(line, encoding))
             for entry in cl.entries:
                 if entry.date:
-                    edate = strptime(entry.date, '%Y-%m-%d')
+                    edate = todate(strptime(entry.date, '%Y-%m-%d'))
                 else:
-                    edate = date.today()
+                    edate = today
                 messages = []
                 for msglines, submsgs in entry.messages:
                     msgstr = unicode(' '.join(l.strip() for l in msglines), encoding)
@@ -225,7 +226,7 @@
                 fdate = self.format_date(edate)
                 w(u'\n%s' % fdate)
                 w('~' * len(fdate))
-                latestdate = date
+                latestdate = edate
             for msg in messages:
                 w(u'* %s' % msg)
                 i += 1
--- a/web/widgets.py	Wed Apr 15 17:00:58 2009 +0200
+++ b/web/widgets.py	Wed Apr 15 17:30:03 2009 +0200
@@ -409,7 +409,7 @@
             entity.req.fckeditor_config()
             if with_format:
                 if entity.has_eid():
-                    format = entity.attribute_metadata(self.name, 'format')
+                    format = entity.attr_metadata(self.name, 'format')
                 else:
                     format = ''
                 frname = eid_param(self.name + '_format', entity.eid)
@@ -513,14 +513,14 @@
     
     def _edit_render(self, entity):
         wdgs = [self._file_wdg(entity)]
-        if entity.attribute_metadata(self.name, 'format') in ('text/plain', 'text/html', 'text/rest'):
+        if entity.attr_metadata(self.name, 'format') in ('text/plain', 'text/html', 'text/rest'):
             msg = self._edit_msg(entity)
             wdgs.append(u'<p><b>%s</b></p>' % msg)
             twdg = TextWidget(self.vreg, self.subjtype, self.rschema, self.objtype)
             twdg.rname = self.rname
             data = getattr(entity, self.name)
             if data:
-                encoding = entity.attribute_metadata(self.name, 'encoding')
+                encoding = entity.attr_metadata(self.name, 'encoding')
                 try:
                     entity[self.name] = unicode(data.getvalue(), encoding)
                 except UnicodeError: