backport stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Thu, 08 Sep 2011 18:09:36 +0200
changeset 7776 aa547cf3bf0d
parent 7769 8af09eeee130 (current diff)
parent 7775 72699a8e739d (diff)
child 7784 7f5c455ec7d1
backport stable
web/webconfig.py
--- a/.hgtags	Wed Sep 07 17:50:09 2011 +0200
+++ b/.hgtags	Thu Sep 08 18:09:36 2011 +0200
@@ -221,3 +221,5 @@
 223ecf0620b6c87d997f8011aca0d9f0ee4750af cubicweb-version-3.13.4
 52f26475d764129c5559b2d80fd57e6ea1bdd6ba cubicweb-debian-version-3.13.4-1
 a62f24e1497e953fbaed5894f6064a64f7ac0be3 cubicweb-version-3.10.x
+20d9c550c57eb6f9adcb0cfab1c11b6b8793afb6 cubicweb-version-3.13.5
+2e9dd7d945557c210d3b79153c65f6885e755315 cubicweb-debian-version-3.13.5-1
--- a/__pkginfo__.py	Wed Sep 07 17:50:09 2011 +0200
+++ b/__pkginfo__.py	Thu Sep 08 18:09:36 2011 +0200
@@ -22,7 +22,7 @@
 
 modname = distname = "cubicweb"
 
-numversion = (3, 13, 4)
+numversion = (3, 13, 5)
 version = '.'.join(str(num) for num in numversion)
 
 description = "a repository of entities / relations for knowledge management"
@@ -40,7 +40,7 @@
 ]
 
 __depends__ = {
-    'logilab-common': '>= 0.55.2',
+    'logilab-common': '>= 0.56.2',
     'logilab-mtconverter': '>= 0.8.0',
     'rql': '>= 0.28.0',
     'yams': '>= 0.33.0',
--- a/debian/changelog	Wed Sep 07 17:50:09 2011 +0200
+++ b/debian/changelog	Thu Sep 08 18:09:36 2011 +0200
@@ -1,3 +1,9 @@
+cubicweb (3.13.5-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Sylvain Thénault <sylvain.thenault@logilab.fr>  Thu, 08 Sep 2011 16:53:13 +0200
+
 cubicweb (3.13.4-1) unstable; urgency=low
 
   * new upstream release
--- a/debian/control	Wed Sep 07 17:50:09 2011 +0200
+++ b/debian/control	Thu Sep 08 18:09:36 2011 +0200
@@ -7,9 +7,9 @@
            Adrien Di Mascio <Adrien.DiMascio@logilab.fr>,
            Aurélien Campéas <aurelien.campeas@logilab.fr>,
            Nicolas Chauvat <nicolas.chauvat@logilab.fr>
-Build-Depends: debhelper (>= 7), python (>= 2.5), python-central (>= 0.5)
+Build-Depends: debhelper (>= 7), python (>= 2.5), python-central (>= 0.5), python-sphinx
 # for the documentation:
-# python-sphinx, python-logilab-common, python-unittest2,
+# python-sphinx, python-logilab-common, python-unittest2, logilab-doctools, logilab-xml
 Standards-Version: 3.9.1
 Homepage: http://www.cubicweb.org
 XS-Python-Version: >= 2.5, << 2.7
@@ -35,7 +35,7 @@
 Conflicts: cubicweb-multisources
 Replaces: cubicweb-multisources
 Provides: cubicweb-multisources
-Depends: ${misc:Depends}, ${python:Depends}, cubicweb-common (= ${source:Version}), cubicweb-ctl (= ${source:Version}), python-logilab-database (>= 1.5.0), cubicweb-postgresql-support | cubicweb-mysql-support | python-pysqlite2
+Depends: ${misc:Depends}, ${python:Depends}, cubicweb-common (= ${source:Version}), cubicweb-ctl (= ${source:Version}), python-logilab-database (>= 1.5.0), cubicweb-postgresql-support | cubicweb-mysql-support | python-pysqlite2, python-logilab-common (>= 0.56.2)
 Recommends: pyro (<< 4.0.0), cubicweb-documentation (= ${source:Version})
 Description: server part of the CubicWeb framework
  CubicWeb is a semantic web application framework.
@@ -70,7 +70,7 @@
 Architecture: all
 XB-Python-Version: ${python:Versions}
 Provides: cubicweb-web-frontend
-Depends: ${misc:Depends}, ${python:Depends}, cubicweb-web (= ${source:Version}), cubicweb-ctl (= ${source:Version}), python-twisted-web
+Depends: ${misc:Depends}, ${python:Depends}, cubicweb-web (= ${source:Version}), cubicweb-ctl (= ${source:Version}), python-twisted-web, python-logilab-common (>= 0.56.2)
 Recommends: pyro (<< 4.0.0), cubicweb-documentation (= ${source:Version})
 Description: twisted-based web interface for the CubicWeb framework
  CubicWeb is a semantic web application framework.
--- a/debian/rules	Wed Sep 07 17:50:09 2011 +0200
+++ b/debian/rules	Thu Sep 08 18:09:36 2011 +0200
@@ -10,14 +10,11 @@
 build: build-stamp
 build-stamp:
 	dh_testdir
-	# XXX doesn't work if logilab-doctools, logilab-xml are not in build depends
-	# and I can't get pbuilder find them in its chroot :(
-	# cd doc && make
-	# FIXME cleanup and use sphinx-build as build-depends ?
 	NO_SETUPTOOLS=1 python setup.py build
-	# XXX uncomment this and associated build-depends in control
-	#when necessary sphinx version is in all built distribution
-	#PYTHONPATH=$(CURDIR)/.. $(MAKE) -C doc/book/en all
+	# documentation build is now made optional since it can break for old
+	# distributions and we don't want to block a new release of Cubicweb
+	# because of documentation issues.
+	-PYTHONPATH=$(CURDIR)/.. $(MAKE) -C doc/book/en all
 	touch build-stamp
 
 clean:
@@ -73,7 +70,7 @@
 	dh_installman -i
 	dh_installchangelogs -i
 	dh_link -i
-	dh_compress -i -X.py -X.ini -X.xml
+	dh_compress -i -X.py -X.ini -X.xml -X.js -X.rst
 	dh_fixperms -i
 	dh_installdeb -i
 	dh_gencontrol  -i
--- a/devtools/__init__.py	Wed Sep 07 17:50:09 2011 +0200
+++ b/devtools/__init__.py	Thu Sep 08 18:09:36 2011 +0200
@@ -672,8 +672,9 @@
         if 'global-db-name' not in self.system_source:
             self.system_source['global-db-name'] = self.system_source['db-name']
             process_db = self.system_source['db-name'] + str(os.getpid())
-            self.__TMPDB.add(process_db)
             self.system_source['db-name'] = process_db
+        process_db = self.absolute_dbfile() # update db-name to absolute path
+        self.__TMPDB.add(process_db)
 
     @staticmethod
     def _cleanup_database(dbfile):
@@ -694,7 +695,6 @@
         self.config.sources()['system']['db-name'] = dbfile
         return dbfile
 
-
     def process_cache_entry(self, directory, dbname, db_id, entry):
         return entry.get('sqlite')
 
--- a/devtools/testlib.py	Wed Sep 07 17:50:09 2011 +0200
+++ b/devtools/testlib.py	Thu Sep 08 18:09:36 2011 +0200
@@ -493,7 +493,7 @@
 
     def assertModificationDateGreater(self, entity, olddate):
         entity.cw_attr_cache.pop('modification_date', None)
-        self.failUnless(entity.modification_date > olddate)
+        self.assertTrue(entity.modification_date > olddate)
 
     def assertItemsEqual(self, it1, it2, *args, **kwargs):
         it1 = set(getattr(x, 'eid', x) for x in it1)
--- a/etwist/server.py	Wed Sep 07 17:50:09 2011 +0200
+++ b/etwist/server.py	Thu Sep 08 18:09:36 2011 +0200
@@ -25,7 +25,6 @@
 import os
 import os.path as osp
 import select
-import errno
 import traceback
 import threading
 import re
@@ -523,12 +522,8 @@
             return whichproc # parent process
     root_resource.init_publisher() # before changing uid
     if config['uid'] is not None:
-        try:
-            uid = int(config['uid'])
-        except ValueError:
-            from pwd import getpwnam
-            uid = getpwnam(config['uid']).pw_uid
-        os.setuid(uid)
+        from logilab.common.daemon import setugid
+        setugid(config['uid'])
     root_resource.start_service()
     LOGGER.info('instance started on %s', root_resource.base_url)
     # avoid annoying warnign if not in Main Thread
--- a/i18n/de.po	Wed Sep 07 17:50:09 2011 +0200
+++ b/i18n/de.po	Thu Sep 08 18:09:36 2011 +0200
@@ -1974,6 +1974,9 @@
 msgid "data directory url"
 msgstr "URL des Daten-Pools"
 
+msgid "data model schema"
+msgstr "Schema der Website"
+
 msgid "data sources"
 msgstr ""
 
@@ -3755,9 +3758,6 @@
 msgid "site documentation"
 msgstr "Dokumentation der Website"
 
-msgid "data model schema"
-msgstr "Schema der Website"
-
 msgid "site title"
 msgstr "Titel der Website"
 
--- a/i18n/en.po	Wed Sep 07 17:50:09 2011 +0200
+++ b/i18n/en.po	Thu Sep 08 18:09:36 2011 +0200
@@ -1929,6 +1929,9 @@
 msgid "data directory url"
 msgstr ""
 
+msgid "data model schema"
+msgstr ""
+
 msgid "data sources"
 msgstr ""
 
@@ -3659,9 +3662,6 @@
 msgid "site documentation"
 msgstr ""
 
-msgid "data model schema"
-msgstr ""
-
 msgid "site title"
 msgstr ""
 
--- a/i18n/es.po	Wed Sep 07 17:50:09 2011 +0200
+++ b/i18n/es.po	Thu Sep 08 18:09:36 2011 +0200
@@ -2003,6 +2003,9 @@
 msgid "data directory url"
 msgstr "Url del repertorio de datos"
 
+msgid "data model schema"
+msgstr "Esquema del Sistema"
+
 msgid "data sources"
 msgstr "fuente de datos"
 
@@ -3806,9 +3809,6 @@
 msgid "site documentation"
 msgstr "Documentación Sistema"
 
-msgid "data model schema"
-msgstr "Esquema del Sistema"
-
 msgid "site title"
 msgstr "Nombre del Sistema"
 
--- a/i18n/fr.po	Wed Sep 07 17:50:09 2011 +0200
+++ b/i18n/fr.po	Thu Sep 08 18:09:36 2011 +0200
@@ -164,7 +164,9 @@
 #, python-format
 msgid ""
 "'%s' action for in_state relation should at least have 'linkattr=name' option"
-msgstr "l'action '%s' pour la relation in_state doit au moins avoir l'option 'linkattr=name'"
+msgstr ""
+"l'action '%s' pour la relation in_state doit au moins avoir l'option "
+"'linkattr=name'"
 
 #, python-format
 msgid "'%s' action requires 'linkattr' option"
@@ -1260,7 +1262,8 @@
 msgstr "automatique"
 
 msgid "autocomputed attribute used to ensure transition coherency"
-msgstr "attribut calculé automatiquement pour assurer la cohérence de la transition"
+msgstr ""
+"attribut calculé automatiquement pour assurer la cohérence de la transition"
 
 msgid "automatic"
 msgstr "automatique"
@@ -2006,6 +2009,9 @@
 msgid "data directory url"
 msgstr "url du répertoire de données"
 
+msgid "data model schema"
+msgstr "schéma du modèle de données"
+
 msgid "data sources"
 msgstr "sources de données"
 
@@ -3677,7 +3683,8 @@
 msgstr "expression rql autorisant à lire des entités/relations de ce type"
 
 msgid "rql expression allowing to update entities/relations of this type"
-msgstr "expression rql autorisant à mettre à jour des entités/relations de ce type"
+msgstr ""
+"expression rql autorisant à mettre à jour des entités/relations de ce type"
 
 msgid "rql expressions"
 msgstr "conditions rql"
@@ -3806,9 +3813,6 @@
 msgid "site documentation"
 msgstr "documentation du site"
 
-msgid "data model schema"
-msgstr "schéma modèle de données"
-
 msgid "site title"
 msgstr "titre du site"
 
--- a/server/msplanner.py	Wed Sep 07 17:50:09 2011 +0200
+++ b/server/msplanner.py	Thu Sep 08 18:09:36 2011 +0200
@@ -1623,17 +1623,7 @@
     def visit_relation(self, node, newroot, terms):
         if not node.is_types_restriction():
             if not node in terms and node in self.skip and self.solindices.issubset(self.skip[node]):
-                if not self.schema.rschema(node.r_type).final:
-                    # can't really skip the relation if one variable is selected
-                    # and only referenced by this relation
-                    for vref in node.iget_nodes(VariableRef):
-                        stinfo = vref.variable.stinfo
-                        if stinfo['selected'] and len(stinfo['relations']) == 1:
-                            break
-                    else:
-                        return None, node
-                else:
-                    return None, node
+                return None, node
             if not self._relation_supported(node):
                 raise UnsupportedBranch()
         # don't copy type restriction unless this is the only supported relation
--- a/server/serverctl.py	Wed Sep 07 17:50:09 2011 +0200
+++ b/server/serverctl.py	Thu Sep 08 18:09:36 2011 +0200
@@ -651,7 +651,7 @@
         )
 
     def run(self, args):
-        from logilab.common.daemon import daemonize
+        from logilab.common.daemon import daemonize, setugid
         from cubicweb.cwctl import init_cmdline_log_threshold
         from cubicweb.server.server import RepositoryServer
         appid = args[0]
@@ -675,12 +675,7 @@
             return
         uid = config['uid']
         if uid is not None:
-            try:
-                uid = int(uid)
-            except ValueError:
-                from pwd import getpwnam
-                uid = getpwnam(uid).pw_uid
-            os.setuid(uid)
+            setugid(uid)
         server.install_sig_handlers()
         server.connect(config['host'], 0)
         server.run()
--- a/server/test/unittest_msplanner.py	Wed Sep 07 17:50:09 2011 +0200
+++ b/server/test/unittest_msplanner.py	Thu Sep 08 18:09:36 2011 +0200
@@ -1212,12 +1212,12 @@
                                     [{'X': 'Note', 'S': 'State'}])],
                      [self.cards, self.system], None, {'X': 'table0.C0', 'S': 'table0.C1'}, []),
                      ('UnionStep', None, None,
-                      [('OneFetchStep', [('Any X,S,U WHERE X in_state S, X todo_by U, S is State, U is CWUser, X is Note',
+                      [('OneFetchStep', [('Any X,S,U WHERE X in_state S, X todo_by U, S is State, U is Personne, X is Affaire',
+                                          [{'X': 'Affaire', 'S': 'State', 'U': 'Personne'}])],
+                        None, None, [self.system], {}, []),
+                       ('OneFetchStep', [('Any X,S,U WHERE X todo_by U, S is State, U is CWUser, X is Note',
                                           [{'X': 'Note', 'S': 'State', 'U': 'CWUser'}])],
                         None, None, [self.system], {'X': 'table0.C0', 'S': 'table0.C1'}, []),
-                       ('OneFetchStep', [('Any X,S,U WHERE X in_state S, X todo_by U, S is State, U is Personne, X is Affaire',
-                                          [{'X': 'Affaire', 'S': 'State', 'U': 'Personne'}])],
-                        None, None, [self.system], {}, []),
                        ])
                     ])
 
@@ -2456,6 +2456,21 @@
                      [])],
                    {'x': 999999})
 
+    def test_nonregr_dont_readd_already_processed_relation(self):
+        self._test('Any WO,D,SO WHERE WO is Note, D tags WO, WO in_state SO',
+                   [('FetchStep',
+                     [('Any WO,SO WHERE WO in_state SO, SO is State, WO is Note',
+                       [{'SO': 'State', 'WO': 'Note'}])],
+                     [self.cards, self.system], None,
+                     {'SO': 'table0.C1', 'WO': 'table0.C0'},
+                     []),
+                    ('OneFetchStep',
+                     [('Any WO,D,SO WHERE D tags WO, D is Tag, SO is State, WO is Note',
+                       [{'D': 'Tag', 'SO': 'State', 'WO': 'Note'}])],
+                     None, None, [self.system],
+                     {'SO': 'table0.C1', 'WO': 'table0.C0'},
+                     [])
+                    ])
 
 class MSPlannerTwoSameExternalSourcesTC(BasePlannerTC):
     """test planner related feature on a 3-sources repository:
--- a/server/test/unittest_multisources.py	Wed Sep 07 17:50:09 2011 +0200
+++ b/server/test/unittest_multisources.py	Thu Sep 08 18:09:36 2011 +0200
@@ -381,6 +381,9 @@
     def test_nonregr3(self):
         self.sexecute('DELETE Card X WHERE X eid %(x)s, NOT X multisource_inlined_rel Y', {'x': self.ic1})
 
+    def test_nonregr4(self):
+        self.sexecute('Any X,S,U WHERE X in_state S, X todo_by U')
+
     def test_delete_source(self):
         req = self.request()
         req.execute('DELETE CWSource S WHERE S name "extern"')
--- a/web/facet.py	Wed Sep 07 17:50:09 2011 +0200
+++ b/web/facet.py	Thu Sep 08 18:09:36 2011 +0200
@@ -66,7 +66,7 @@
 from cubicweb.utils import make_uid
 from cubicweb.selectors import match_context_prop, partial_relation_possible
 from cubicweb.appobject import AppObject
-from cubicweb.web.htmlwidgets import HTMLWidget
+from cubicweb.web import RequestError, htmlwidgets
 
 
 def rtype_facet_title(facet):
@@ -431,7 +431,7 @@
         values are selected.
         """
         # OR between selected values by default
-        return self._cw.form.get(self.__regid__ + '_andor', 'OR')
+        return self._cw.form.get(xml_escape(self.__regid__) + '_andor', 'OR')
 
     def rqlexec(self, rql, args=None):
         """Utility method to execute some rql queries, and simply returning an
@@ -720,6 +720,7 @@
         return support
 
     def value_restriction(self, restrvar, rel, value):
+        # XXX handle rel is None case in RQLPathFacet?
         if self.restr_attr != 'eid':
             self.select.set_distinct(True)
         if isinstance(value, basestring):
@@ -740,14 +741,19 @@
                 self._add_not_rel_restr(rel)
             self._and_restriction(rel, restrvar, value)
         else:
-            # multiple values with AND operator
+            # multiple values with AND operator. We've to generate a query like
+            # "X relation A, A eid 1, X relation B, B eid 1", hence the new
+            # relations at each iteration in the while loop below 
             if '' in value:
-                value.remove('')
-                self._add_not_rel_restr(rel)
+                raise RequestError("this doesn't make sense")
             self._and_restriction(rel, restrvar, value.pop())
             while value:
                 restrvar, rtrel = _make_relation(self.select, self.filtered_variable,
                                                  self.rtype, self.role)
+                if rel is None:
+                    select.add_restriction(rtrel)
+                else:
+                    rel.parent.replace(rel, nodes.And(rel, rtrel))
                 self._and_restriction(rel, restrvar, value.pop())
 
     def _and_restriction(self, rel, restrvar, value):
@@ -1331,7 +1337,7 @@
 
 ## html widets ################################################################
 
-class FacetVocabularyWidget(HTMLWidget):
+class FacetVocabularyWidget(htmlwidgets.HTMLWidget):
 
     def __init__(self, facet):
         self.facet = facet
@@ -1355,7 +1361,7 @@
             w(u'''<select name="%s" class="radio facetOperator" title="%s">
   <option value="OR">%s</option>
   <option value="AND">%s</option>
-</select>''' % (facetid + '_andor', _('and/or between different values'),
+</select>''' % (xml_escape(self.facet.__regid__) + '_andor', _('and/or between different values'),
                 _('OR'), _('AND')))
         cssclass = 'facetBody'
         if not self.facet.start_unfolded:
@@ -1369,7 +1375,7 @@
         w(u'</div>\n')
 
 
-class FacetStringWidget(HTMLWidget):
+class FacetStringWidget(htmlwidgets.HTMLWidget):
     def __init__(self, facet):
         self.facet = facet
         self.value = None
@@ -1388,7 +1394,7 @@
         w(u'</div>\n')
 
 
-class FacetRangeWidget(HTMLWidget):
+class FacetRangeWidget(htmlwidgets.HTMLWidget):
     formatter = 'function (value) {return value;}'
     onload = u'''
     var _formatter = %(formatter)s;
@@ -1478,7 +1484,7 @@
         facet._cw.html_headers.define_var('DATE_FMT', fmt)
 
 
-class FacetItem(HTMLWidget):
+class FacetItem(htmlwidgets.HTMLWidget):
 
     selected_img = "black-check.png"
     unselected_img = "no-check-no-border.png"
@@ -1506,7 +1512,7 @@
         w(u'</div>')
 
 
-class CheckBoxFacetWidget(HTMLWidget):
+class CheckBoxFacetWidget(htmlwidgets.HTMLWidget):
     selected_img = "black-check.png"
     unselected_img = "black-uncheck.png"
 
@@ -1543,7 +1549,7 @@
         w(u'</div>\n')
 
 
-class FacetSeparator(HTMLWidget):
+class FacetSeparator(htmlwidgets.HTMLWidget):
     def __init__(self, label=None):
         self.label = label or u'&#160;'
 
--- a/web/test/unittest_facet.py	Wed Sep 07 17:50:09 2011 +0200
+++ b/web/test/unittest_facet.py	Thu Sep 08 18:09:36 2011 +0200
@@ -50,6 +50,22 @@
         self.assertEqual(f.select.as_string(),
                          'DISTINCT Any  WHERE X is CWUser, X in_group D, D eid %s' % guests)
 
+    def test_relation_multiple_and(self):
+        f, (guests, managers) = self._in_group_facet()
+        f._cw.form[f.__regid__] = [str(guests), str(managers)]
+        f._cw.form[f.__regid__ + '_andor'] = 'AND'
+        f.add_rql_restrictions()
+        self.assertEqual(f.select.as_string(),
+                         'DISTINCT Any  WHERE X is CWUser, X in_group A, B eid %s, X in_group B, A eid %s' % (guests, managers))
+
+    def test_relation_multiple_or(self):
+        f, (guests, managers) = self._in_group_facet()
+        f._cw.form[f.__regid__] = [str(guests), str(managers)]
+        f._cw.form[f.__regid__ + '_andor'] = 'OR'
+        f.add_rql_restrictions()
+        self.assertEqual(f.select.as_string(),
+                         'DISTINCT Any  WHERE X is CWUser, X in_group A, A eid IN(%s, %s)' % (guests, managers))
+
     def test_relation_optional_rel(self):
         req = self.request()
         rset = self.execute('Any X,GROUP_CONCAT(GN) GROUPBY X '
--- a/web/views/navigation.py	Wed Sep 07 17:50:09 2011 +0200
+++ b/web/views/navigation.py	Thu Sep 08 18:09:36 2011 +0200
@@ -211,6 +211,14 @@
     context = 'navbottom'
     order = 10
 
+    @property
+    def prev_icon(self):
+        return '<img src="%s"/>' % xml_escape(self._cw.data_url('go_prev.png'))
+
+    @property
+    def next_icon(self):
+        return '<img src="%s"/>' % xml_escape(self._cw.data_url('go_next.png'))
+
     def init_rendering(self):
         adapter = self.entity.cw_adapt_to('IPrevNext')
         self.previous = adapter.previous_entity()
@@ -232,16 +240,19 @@
 
     def prevnext_entity(self, w, entity, type):
         textsize = self._cw.property_value('navigation.short-line-size')
+        content = xml_escape(cut(entity.dc_title(), textsize))
         if type == 'prev':
             title = self._cw._('i18nprevnext_previous')
-            icon = u'&lt;&lt; '
+            icon = self.prev_icon
             cssclass = u'previousEntity left'
+            content = icon + content
         else:
             title = self._cw._('i18nprevnext_next')
-            icon = u'&gt;&gt; '
+            icon = self.next_icon
             cssclass = u'nextEntity right'
+            content = content + '&#160;&#160;' + icon
         self.prevnext_div(w, type, cssclass, entity.absolute_url(),
-                          title, icon + xml_escape(cut(entity.dc_title(), textsize)))
+                          title, content)
 
     def prevnext_div(self, w, type, cssclass, url, title, content):
         w(u'<div class="%s">' % cssclass)
--- a/web/webconfig.py	Wed Sep 07 17:50:09 2011 +0200
+++ b/web/webconfig.py	Thu Sep 08 18:09:36 2011 +0200
@@ -27,6 +27,7 @@
 from logilab.common.decorators import cached
 from logilab.common.deprecation import deprecated
 
+from cubicweb import ConfigurationError
 from cubicweb.toolsutils import read_config
 from cubicweb.cwconfig import CubicWebConfiguration, register_persistent_options, merge_options
 
@@ -239,16 +240,20 @@
         return self.repository().get_versions()
 
     def anonymous_user(self):
-        """return a login and password to use for anonymous users. None
-        may be returned for both if anonymous connections are not allowed
+        """return a login and password to use for anonymous users.
+        
+        None may be returned for both if anonymous connection is not
+        allowed or if an empty login is used in configuration
         """
         try:
-            user = self['anonymous-user']
+            user   = self['anonymous-user'] or None
             passwd = self['anonymous-password']
+            if user:
+                user = unicode(user)
         except KeyError:
             user, passwd = None, None
-        if user is not None:
-            user = unicode(user)
+        except UnicodeDecodeError:
+            raise ConfigurationError("anonymous information should only contains ascii")
         return user, passwd
 
     def locate_resource(self, rid):