backport 3.5
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Fri, 11 Sep 2009 15:57:34 +0200
changeset 3185 bd0126d17e83
parent 3163 edfe43ceaa35 (current diff)
parent 3184 613064b49331 (diff)
child 3195 a6f1daddfe8a
backport 3.5
__pkginfo__.py
common/uilib.py
cwctl.py
cwvreg.py
entity.py
etwist/server.py
etwist/twctl.py
server/serverctl.py
web/test/unittest_form.py
web/test/unittest_urlrewrite.py
web/uicfg.py
web/views/basecomponents.py
web/views/basetemplates.py
web/views/baseviews.py
web/views/editcontroller.py
web/views/editviews.py
web/views/ibreadcrumbs.py
web/views/xmlrss.py
--- a/.hgtags	Thu Sep 10 08:13:22 2009 +0200
+++ b/.hgtags	Fri Sep 11 15:57:34 2009 +0200
@@ -64,3 +64,5 @@
 52dba800ca4d4b82c47f3befb824bd91ef015368 cubicweb-debian-version-3.4.6-1
 0e549b299f0b357837ea620c561aa843f46de17a cubicweb-version-3.4.7
 ebb92e62eb040a070deb1f2d2434734cfac3af01 cubicweb-debian-version-3.4.7-1
+ba43e084e8841f62c3b4c2449b26a7546233e5fb cubicweb-version-3.4.8
+97273eeaaead11c0f422dc5a4fe2d4f14fc6a2dd cubicweb-debian-version-3.4.8-1
--- a/common/uilib.py	Thu Sep 10 08:13:22 2009 +0200
+++ b/common/uilib.py	Fri Sep 11 15:57:34 2009 +0200
@@ -31,7 +31,7 @@
     return 'Any X WHERE X eid %s' % eid
 
 
-def printable_value(req, attrtype, value, props=None, displaytime=True):
+def printable_value(req, attrtype, value, props=None):
     """return a displayable value (i.e. unicode string)"""
     if value is None or attrtype == 'Bytes':
         return u''
@@ -46,8 +46,6 @@
     if attrtype == 'Time':
         return ustrftime(value, req.property_value('ui.time-format'))
     if attrtype == 'Datetime':
-        if not displaytime:
-            return ustrftime(value, req.property_value('ui.date-format'))
         return ustrftime(value, req.property_value('ui.datetime-format'))
     if attrtype == 'Boolean':
         if value:
--- a/cwctl.py	Thu Sep 10 08:13:22 2009 +0200
+++ b/cwctl.py	Fri Sep 11 15:57:34 2009 +0200
@@ -153,6 +153,7 @@
             else:
                 self.run_arg(appid)
 
+
 # base commands ###############################################################
 
 class ListCommand(Command):
@@ -366,7 +367,7 @@
 
 # instance commands ########################################################
 
-class StartInstanceCommand(InstanceCommand):
+class StartInstanceCommand(InstanceCommandFork):
     """Start the given instances. If no instance is given, start them all.
 
     <instance>...
@@ -398,17 +399,15 @@
 
     def start_instance(self, appid):
         """start the instance's server"""
-        # use get() since start may be used from other commands (eg upgrade)
-        # without all options defined
-        debug = self.get('debug')
-        force = self.get('force')
-        loglevel = self.get('loglevel')
+        debug = self['debug']
+        force = self['force']
+        loglevel = self['loglevel']
         config = cwcfg.config_for(appid)
         if loglevel is not None:
             loglevel = 'LOG_%s' % loglevel.upper()
             config.global_set_option('log-threshold', loglevel)
             config.init_log(loglevel, debug=debug, force=True)
-        if self.get('profile'):
+        if self['profile']:
             config.global_set_option('profile', self.config.profile)
         helper = self.config_helper(config, cmdname='start')
         pidf = config['pid-file']
@@ -416,8 +415,10 @@
             msg = "%s seems to be running. Remove %s by hand if necessary or use \
 the --force option."
             raise ExecutionError(msg % (appid, pidf))
-        helper.start_command(config, debug)
-        return True
+        helper.start_server(config, debug)
+        if not debug:
+            # in debug mode, we reach this point once the instance is stopped...
+            print 'instance %s %s' % (appid, self.actionverb)
 
 
 class StopInstanceCommand(InstanceCommand):
@@ -470,8 +471,7 @@
         print 'instance %s stopped' % appid
 
 
-class RestartInstanceCommand(StartInstanceCommand,
-                                StopInstanceCommand):
+class RestartInstanceCommand(StartInstanceCommand):
     """Restart the given instances.
 
     <instance>...
@@ -490,14 +490,12 @@
         print ('some specific start order is specified, will first stop all '
                'instances then restart them.')
         # get instances in startorder
-        stopped = []
         for appid in args:
             if askconfirm:
                 print '*'*72
                 if not ASK.confirm('%s instance %r ?' % (self.name, appid)):
                     continue
-            self.stop_instance(appid)
-            stopped.append(appid)
+            StopInstanceCommand().stop_instance(appid)
         forkcmd = [w for w in sys.argv if not w in args]
         forkcmd[1] = 'start'
         forkcmd = ' '.join(forkcmd)
@@ -507,9 +505,8 @@
                 sys.exit(status)
 
     def restart_instance(self, appid):
-        self.stop_instance(appid)
-        if self.start_instance(appid):
-            print 'instance %s %s' % (appid, self.actionverb)
+        StopInstanceCommand().stop_instance(appid)
+        self.start_instance(appid)
 
 
 class ReloadConfigurationCommand(RestartInstanceCommand):
@@ -560,9 +557,7 @@
             print "running with pid %s" % (pid)
 
 
-class UpgradeInstanceCommand(InstanceCommandFork,
-                                StartInstanceCommand,
-                                StopInstanceCommand):
+class UpgradeInstanceCommand(InstanceCommandFork):
     """Upgrade an instance after cubicweb and/or component(s) upgrade.
 
     For repository update, you will be prompted for a login / password to use
@@ -618,10 +613,6 @@
           }),
         )
 
-    def ordered_instances(self):
-        # need this since mro return StopInstanceCommand implementation
-        return InstanceCommand.ordered_instances(self)
-
     def upgrade_instance(self, appid):
         print '\n' + underline_title('Upgrading the instance %s' % appid)
         from logilab.common.changelog import Version
@@ -668,7 +659,7 @@
             print '-> migration needed from %s to %s for %s' % (fromversion, toversion, cube)
         # only stop once we're sure we have something to do
         if not (cwcfg.mode == 'dev' or self.config.nostartstop):
-            self.stop_instance(appid)
+            StopCommand().stop_instance(appid)
         # run cubicweb/componants migration scripts
         mih.migrate(vcconf, reversed(toupgrade), self.config)
         # rewrite main configuration file
@@ -691,7 +682,7 @@
         print
         print '-> instance migrated.'
         if not (cwcfg.mode == 'dev' or self.config.nostartstop):
-            self.start_instance(appid)
+            StartCommand().start_instance(appid)
         print
 
 
--- a/cwvreg.py	Thu Sep 10 08:13:22 2009 +0200
+++ b/cwvreg.py	Fri Sep 11 15:57:34 2009 +0200
@@ -138,6 +138,7 @@
         baseschemas = [eschema] + eschema.ancestors()
         # browse ancestors from most specific to most generic and try to find an
         # associated custom entity class
+        cls = None
         for baseschema in baseschemas:
             try:
                 btype = ETYPE_NAME_MAP[baseschema]
--- a/debian/changelog	Thu Sep 10 08:13:22 2009 +0200
+++ b/debian/changelog	Fri Sep 11 15:57:34 2009 +0200
@@ -1,3 +1,15 @@
+cubicweb (3.4.9-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Sylvain Thénault <sylvain.thenault@logilab.fr>  Fri, 11 Sep 2009 14:27:39 +0200
+
+cubicweb (3.4.8-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Sylvain Thénault <sylvain.thenault@logilab.fr>  Thu, 10 Sep 2009 15:27:17 +0200
+
 cubicweb (3.4.7-1) unstable; urgency=low
 
   * new upstream release
--- a/doc/book/en/development/entityclasses/load-sort.rst	Thu Sep 10 08:13:22 2009 +0200
+++ b/doc/book/en/development/entityclasses/load-sort.rst	Fri Sep 11 15:57:34 2009 +0200
@@ -16,18 +16,30 @@
   `None` if we do not want to sort on the attribute given in the parameter.
   By default, the entities are sorted according to their creation date.
 
-* The class method `fetch_unrelated_order(attr, var)` is similar to the
-  method `fetch_order` except that it is essentially used to control
-  the sorting of drop-down lists enabling relations creation in
-  the editing view of an entity.
+* The class method `fetch_unrelated_order(attr, var)` is similar to
+  the method `fetch_order` except that it is essentially used to
+  control the sorting of drop-down lists enabling relations creation
+  in the editing view of an entity. The default implementation uses
+  the modification date. Here's how to adapt it for one entity (sort
+  on the name attribute): ::
+
+   class MyEntity(AnyEntity):
+       fetch_attrs = ('modification_date', 'name')
+
+       @classmethod
+       def fetch_unrelated_order(cls, attr, var):
+           if attr == 'name':
+              return '%s ASC' % var
+           return None
+
 
 The function `fetch_config(fetchattrs, mainattr=None)` simplifies the
 definition of the attributes to load and the sorting by returning a
-list of attributes to pre-load (considering automatically the attributes
-of `AnyEntity`) and a sorting function based on the main attribute
-(the second parameter if specified otherwisethe first attribute from
-the list `fetchattrs`).
-This function is defined in `cubicweb.entities`.
+list of attributes to pre-load (considering automatically the
+attributes of `AnyEntity`) and a sorting function based on the main
+attribute (the second parameter if specified, otherwise the first
+attribute from the list `fetchattrs`). This function is defined in
+`cubicweb.entities`.
 
 For example: ::
 
--- a/entity.py	Thu Sep 10 08:13:22 2009 +0200
+++ b/entity.py	Fri Sep 11 15:57:34 2009 +0200
@@ -321,7 +321,7 @@
         return value
 
     def printable_value(self, attr, value=_marker, attrtype=None,
-                        format='text/html', displaytime=True):
+                        format='text/html'):
         """return a displayable value (i.e. unicode string) which may contains
         html tags
         """
@@ -351,7 +351,7 @@
                 return self.mtc_transform(value.getvalue(), attrformat, format,
                                           encoding)
             return u''
-        value = printable_value(self.req, attrtype, value, props, displaytime)
+        value = printable_value(self.req, attrtype, value, props)
         if format == 'text/html':
             value = xml_escape(value)
         return value
--- a/etwist/server.py	Thu Sep 10 08:13:22 2009 +0200
+++ b/etwist/server.py	Fri Sep 11 15:57:34 2009 +0200
@@ -16,12 +16,6 @@
 import hotshot
 
 from twisted.application import strports
-try:
-    from twisted.scripts._twistd_unix import daemonize
-except ImportError:
-    def daemonize():
-        raise NotImplementedError('not yet for win32')
-
 from twisted.internet import reactor, task, threads
 from twisted.internet.defer import maybeDeferred
 from twisted.web2 import channel, http, server, iweb
@@ -35,6 +29,36 @@
 
 from cubicweb.etwist.request import CubicWebTwistedRequestAdapter
 
+def daemonize(uid):
+    # XXX unix specific
+    # XXX factorize w/ code in cw.server.server and cw.server.serverctl
+    # (start-repository command)
+    if uid is not None:
+        try:
+            uid = int(uid)
+        except ValueError:
+            from pwd import getpwnam
+            uid = getpwnam(uid).pw_uid
+        os.setuid(uid)
+    # See http://www.erlenstar.demon.co.uk/unix/faq_toc.html#TOC16
+    if os.fork():   # launch child and...
+        return -1
+    os.setsid()
+    if os.fork():   # launch child and...
+        os._exit(0) # kill off parent again.
+    # move to the root to avoit mount pb
+    os.chdir('/')
+    # set paranoid umask
+    os.umask(077)
+    null = os.open('/dev/null', os.O_RDWR)
+    for i in range(3):
+        try:
+            os.dup2(null, i)
+        except OSError, e:
+            if e.errno != errno.EBADF:
+                raise
+    os.close(null)
+    return None
 
 def start_task(interval, func):
     lc = task.LoopingCall(func)
@@ -373,7 +397,9 @@
     logger = getLogger('cubicweb.twisted')
     logger.info('instance started on %s', baseurl)
     if not debug:
-        daemonize()
+        if daemonize(config['uid']):
+            # child process
+            return
         if config['pid-file']:
             # ensure the directory where the pid-file should be set exists (for
             # instance /var/run/cubicweb may be deleted on computer restart)
--- a/etwist/twctl.py	Thu Sep 10 08:13:22 2009 +0200
+++ b/etwist/twctl.py	Fri Sep 11 15:57:34 2009 +0200
@@ -17,7 +17,7 @@
     cmdname = 'start'
     cfgname = 'twisted'
 
-    def start_command(self, config, debug):
+    def start_server(self, config, debug):
         from cubicweb.etwist import server
         server.run(config, debug)
 
--- a/server/querier.py	Thu Sep 10 08:13:22 2009 +0200
+++ b/server/querier.py	Fri Sep 11 15:57:34 2009 +0200
@@ -508,7 +508,7 @@
             if repo.schema.rschema(rtype).inlined:
                 entity = session.entity_from_eid(subj)
                 entity[rtype] = obj
-                repo.glob_update_entity(session, entity)
+                repo.glob_update_entity(session, entity, set((rtype,)))
             else:
                 repo.glob_add_relation(session, subj, rtype, obj)
 
--- a/server/serverctl.py	Thu Sep 10 08:13:22 2009 +0200
+++ b/server/serverctl.py	Fri Sep 11 15:57:34 2009 +0200
@@ -210,12 +210,12 @@
     cmdname = 'start'
     cfgname = 'repository'
 
-    def start_command(self, ctlconf, debug):
+    def start_server(self, ctlconf, debug):
         command = ['cubicweb-ctl start-repository ']
         if debug:
             command.append('--debug')
         command.append(self.config.appid)
-        return ' '.join(command)
+        os.system(' '.join(command))
 
 
 class RepositoryStopHandler(CommandHandler):
--- a/skeleton/migration/postcreate.py	Thu Sep 10 08:13:22 2009 +0200
+++ b/skeleton/migration/postcreate.py	Fri Sep 11 15:57:34 2009 +0200
@@ -1,4 +1,4 @@
-# postcreate script. You could setup a workflow here for example
+# postcreate script. You could setup site properties or a workflow here for example
 """
 
 :organization: Logilab
@@ -7,3 +7,6 @@
 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
 """
 
+# Example of site property change
+#set_property('ui.site-title', "<sitename>")
+
--- a/web/test/data/bootstrap_cubes	Thu Sep 10 08:13:22 2009 +0200
+++ b/web/test/data/bootstrap_cubes	Fri Sep 11 15:57:34 2009 +0200
@@ -1,1 +1,1 @@
-file, blog, tag
+file, blog, tag, folder
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/unittest_breadcrumbs.py	Fri Sep 11 15:57:34 2009 +0200
@@ -0,0 +1,17 @@
+from cubicweb.devtools.testlib import WebTest
+
+class BreadCrumbsTC(WebTest):
+
+    def test_base(self):
+        f1 = self.add_entity('Folder', name=u'par&ent')
+        f2 = self.add_entity('Folder', name=u'chi&ld')
+        self.execute('SET F2 filed_under F1 WHERE F1 eid %(f1)s, F2 eid %(f2)s',
+                     {'f1' : f1.eid, 'f2' : f2.eid})
+        self.commit()
+        childrset = self.execute('Folder F WHERE F eid %s' % f2.eid)
+        self.assertEquals(childrset.get_entity(0,0).view('breadcrumbs'),
+                          '<a href="http://testing.fr/cubicweb/folder/%s" title="">chi&amp;ld</a>' % f1.eid)
+        ibc = self.vreg['components'].select('breadcrumbs', self.request(), rset=childrset)
+        self.assertEquals(ibc.render(),
+                          """<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;
+chi&amp;ld</span>""" % f2.eid)
--- a/web/test/unittest_form.py	Thu Sep 10 08:13:22 2009 +0200
+++ b/web/test/unittest_form.py	Fri Sep 11 15:57:34 2009 +0200
@@ -54,6 +54,7 @@
         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.vreg['etypes'].etype_class('CWUser')(self.request())
         form = EntityFieldsForm(e.req, None, entity=e)
--- a/web/test/unittest_urlrewrite.py	Thu Sep 10 08:13:22 2009 +0200
+++ b/web/test/unittest_urlrewrite.py	Fri Sep 11 15:57:34 2009 +0200
@@ -106,6 +106,73 @@
         self.assertEquals(len(rset), 1)
         self.assertEquals(rset[0][0], self.p1.eid)
 
+    def test_inheritance_precedence(self):
+        RQL1 = 'Any C WHERE C is CWEType'
+        RQL2 = 'Any C WHERE C is CWUser'
+
+        class BaseRewriter(SchemaBasedRewriter):
+            rules = [
+               (rgx('/collector(.*)'),
+                rgx_action(rql=RQL1,
+                    form=dict(vid='baseindex')),
+                ),
+                ]
+        class Rewriter(BaseRewriter):
+            rules = [
+               (rgx('/collector/something(/?)'),
+                rgx_action(rql=RQL2,
+                    form=dict(vid='index')),
+                ),
+                ]
+
+        rewriter = Rewriter()
+        req = self.request()
+        pmid, rset = rewriter.rewrite(req, '/collector')
+        self.assertEquals(rset.rql, RQL1)
+        self.assertEquals(req.form, {'vid' : "baseindex"})
+        pmid, rset = rewriter.rewrite(req, '/collector/something')
+        self.assertEquals(rset.rql, RQL2)
+        self.assertEquals(req.form, {'vid' : "index"})
+        pmid, rset = rewriter.rewrite(req, '/collector/something/')
+        self.assertEquals(req.form, {'vid' : "index"})
+        self.assertEquals(rset.rql, RQL2)
+        pmid, rset = rewriter.rewrite(req, '/collector/somethingelse/')
+        self.assertEquals(rset.rql, RQL1)
+        self.assertEquals(req.form, {'vid' : "baseindex"})
+
+    def test_inheritance_precedence_same_rgx(self):
+        RQL1 = 'Any C WHERE C is CWEType'
+        RQL2 = 'Any C WHERE C is CWUser'
+
+        class BaseRewriter(SchemaBasedRewriter):
+            rules = [
+               (rgx('/collector(.*)'),
+                rgx_action(rql=RQL1,
+                    form=dict(vid='baseindex')),
+                ),
+                ]
+        class Rewriter(BaseRewriter):
+            rules = [
+               (rgx('/collector(.*)'),
+                rgx_action(rql=RQL2,
+                    form=dict(vid='index')),
+                ),
+                ]
+
+        rewriter = Rewriter()
+        req = self.request()
+        pmid, rset = rewriter.rewrite(req, '/collector')
+        self.assertEquals(rset.rql, RQL2)
+        self.assertEquals(req.form, {'vid' : "index"})
+        pmid, rset = rewriter.rewrite(req, '/collector/something')
+        self.assertEquals(rset.rql, RQL2)
+        self.assertEquals(req.form, {'vid' : "index"})
+        pmid, rset = rewriter.rewrite(req, '/collector/something/')
+        self.assertEquals(req.form, {'vid' : "index"})
+        self.assertEquals(rset.rql, RQL2)
+        pmid, rset = rewriter.rewrite(req, '/collector/somethingelse/')
+        self.assertEquals(rset.rql, RQL2)
+        self.assertEquals(req.form, {'vid' : "index"})
 
 
 if __name__ == '__main__':
--- a/web/uicfg.py	Thu Sep 10 08:13:22 2009 +0200
+++ b/web/uicfg.py	Fri Sep 11 15:57:34 2009 +0200
@@ -166,6 +166,7 @@
             else:
                 self.setdefault(eschema, 'application')
 
+
 indexview_etype_section = InitializableDict(EmailAddress='subobject',
                                             CWUser='system',
                                             CWGroup='system',
--- a/web/views/basecomponents.py	Thu Sep 10 08:13:22 2009 +0200
+++ b/web/views/basecomponents.py	Fri Sep 11 15:57:34 2009 +0200
@@ -149,7 +149,7 @@
         title = self.req.property_value('ui.site-title')
         if title:
             self.w(u'<span id="appliName"><a href="%s">%s</a></span>' % (
-                self.req.base_url(), title))
+                self.req.base_url(), xml_escape(title)))
 
 
 class SeeAlsoVComponent(component.RelatedObjectsVComponent):
--- a/web/views/basetemplates.py	Thu Sep 10 08:13:22 2009 +0200
+++ b/web/views/basetemplates.py	Fri Sep 11 15:57:34 2009 +0200
@@ -479,8 +479,12 @@
         self.req.add_css('cubicweb.login.css')
         self.w(u'<div id="%s" class="%s">' % (id, klass))
         if title:
-            self.w(u'<div id="loginTitle">%s</div>'
-                   % (self.req.property_value('ui.site-title') or u'&#160;'))
+            stitle = self.req.property_value('ui.site-title')
+            if stitle:
+                stitle = xml_escape(stitle)
+            else:
+                stitle = u'&#160;'
+            self.w(u'<div id="loginTitle">%s</div>' % stitle)
         self.w(u'<div id="loginContent">\n')
 
         if message:
--- a/web/views/baseviews.py	Thu Sep 10 08:13:22 2009 +0200
+++ b/web/views/baseviews.py	Fri Sep 11 15:57:34 2009 +0200
@@ -66,7 +66,7 @@
     _('%d minutes')
     _('%d seconds')
 
-    def cell_call(self, row, col, props=None, displaytime=False, format='text/html'):
+    def cell_call(self, row, col, props=None, format='text/html'):
         etype = self.rset.description[row][col]
         value = self.rset.rows[row][col]
 
@@ -98,7 +98,7 @@
             else:
                 self.w(self.req.__('%%d%sseconds' % space) % int(value.seconds))
             return
-        self.wdata(printable_value(self.req, etype, value, props, displaytime=displaytime))
+        self.wdata(printable_value(self.req, etype, value, props))
 
 
 # XXX deprecated
--- a/web/views/csvexport.py	Thu Sep 10 08:13:22 2009 +0200
+++ b/web/views/csvexport.py	Fri Sep 11 15:57:34 2009 +0200
@@ -51,7 +51,7 @@
                                         row=rowindex, col=colindex)
                 else:
                     content = self.view('final', rset,
-                                        displaytime=True, format='text/plain',
+                                        format='text/plain',
                                         row=rowindex, col=colindex)
                 csvrow.append(content)
             writer.writerow(csvrow)
--- a/web/views/editcontroller.py	Thu Sep 10 08:13:22 2009 +0200
+++ b/web/views/editcontroller.py	Fri Sep 11 15:57:34 2009 +0200
@@ -194,19 +194,7 @@
         # NOTE: raising ValidationError here is not a good solution because
         #       we can't gather all errors at once. Hopefully, the new 3.6.x
         #       form handling will fix that
-        if value and attrtype == 'Int':
-            try:
-                value = int(value)
-            except ValueError:
-                raise ValidationError(entity.eid,
-                                      {attr: self.req._("invalid integer value")})
-        elif value and attrtype == 'Float':
-            try:
-                value = float(value)
-            except ValueError:
-                raise ValidationError(entity.eid,
-                                      {attr: self.req._("invalid float value")})
-        elif attrtype == 'Boolean':
+        if attrtype == 'Boolean':
             value = bool(value)
         elif attrtype == 'Decimal':
             value = Decimal(value)
@@ -248,6 +236,18 @@
                 # no specified value, skip
                 return
         elif value is not None:
+            if attrtype == 'Int':
+                try:
+                    value = int(value)
+                except ValueError:
+                    raise ValidationError(entity.eid,
+                                          {attr: self.req._("invalid integer value")})
+            elif attrtype == 'Float':
+                try:
+                    value = float(value)
+                except ValueError:
+                    raise ValidationError(entity.eid,
+                                          {attr: self.req._("invalid float value")})
             if attrtype in ('Date', 'Datetime', 'Time'):
                 try:
                     value = self.parse_datetime(value, attrtype)
--- a/web/views/editviews.py	Thu Sep 10 08:13:22 2009 +0200
+++ b/web/views/editviews.py	Fri Sep 11 15:57:34 2009 +0200
@@ -198,9 +198,9 @@
     """same as FinalView but enables inplace-edition when possible"""
     id = 'editable-final'
 
-    def cell_call(self, row, col, props=None, displaytime=False):
+    def cell_call(self, row, col, props=None):
         entity, rtype = self.rset.related_entity(row, col)
         if entity is not None:
             self.w(entity.view('reledit', rtype=rtype))
         else:
-            super(EditableFinalView, self).cell_call(row, col, props, displaytime)
+            super(EditableFinalView, self).cell_call(row, col, props)
--- a/web/views/ibreadcrumbs.py	Thu Sep 10 08:13:22 2009 +0200
+++ b/web/views/ibreadcrumbs.py	Fri Sep 11 15:57:34 2009 +0200
@@ -56,9 +56,9 @@
     def wpath_part(self, part, contextentity, last=False):
         if isinstance(part, Entity):
             if last and part.eid == contextentity.eid:
-                part.view('breadcrumbtext', w=self.w)
+                self.w(xml_escape(part.view('breadcrumbtext')))
             else:
-                part.view('breadcrumbs', w=self.w)
+                self.w(part.view('breadcrumbs'))
         elif isinstance(part, tuple):
             url, title = part
             textsize = self.req.property_value('navigation.short-line-size')
@@ -99,8 +99,9 @@
     def cell_call(self, row, col):
         entity = self.rset.get_entity(row, col)
         desc = xml_escape(uilib.cut(entity.dc_description(), 50))
-        self.w(tags.a(entity.view('breadcrumbtext'), href=entity.absolute_url(),
-                      title=desc))
+        # XXX remember camember : tags.a autoescapes !
+        self.w(tags.a(entity.view('breadcrumbtext'),
+                      href=entity.absolute_url(), title=desc))
 
 
 class BreadCrumbTextView(EntityView):
--- a/web/views/xmlrss.py	Thu Sep 10 08:13:22 2009 +0200
+++ b/web/views/xmlrss.py	Fri Sep 11 15:57:34 2009 +0200
@@ -95,8 +95,8 @@
                     val = self.view('textincontext', rset,
                                     row=rowindex, col=colindex)
                 else:
-                    val = self.view('final', rset, displaytime=True,
-                                    row=rowindex, col=colindex, format='text/plain')
+                    val = self.view('final', rset, row=rowindex,
+                                    col=colindex, format='text/plain')
                 w(simple_sgml_tag(tag, val, **attrs))
             w(u' </row>\n')
         w(u'</%s>\n' % self.xml_root)