backport stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Fri, 30 Jul 2010 13:18:36 +0200
changeset 6047 ee6deb534f57
parent 6041 31776723c0c5 (current diff)
parent 6046 3fd4a34c4a09 (diff)
child 6055 bb7bd9cafacf
backport stable
view.py
--- a/cwvreg.py	Fri Jul 30 10:09:31 2010 +0200
+++ b/cwvreg.py	Fri Jul 30 13:18:36 2010 +0200
@@ -205,7 +205,7 @@
                       ObjectNotFound, NoSelectableObject, RegistryNotFound,
                       CW_EVENT_MANAGER)
 from cubicweb.utils import dump_class
-from cubicweb.vregistry import VRegistry, Registry, class_regid
+from cubicweb.vregistry import VRegistry, Registry, class_regid, classid
 from cubicweb.rtags import RTAGS
 
 def clear_rtag_objects():
@@ -310,11 +310,10 @@
     @cached
     def parent_classes(self, etype):
         if etype == 'Any':
-            return [self.etype_class('Any')]
-        eschema = self.schema.eschema(etype)
-        parents = [self.etype_class(e.type) for e in eschema.ancestors()]
-        parents.append(self.etype_class('Any'))
-        return parents
+            return (), self.etype_class('Any')
+        parents = tuple(self.etype_class(e.type)
+                        for e in self.schema.eschema(etype).ancestors())
+        return parents, self.etype_class('Any')
 
     @cached
     def etype_class(self, etype):
@@ -617,7 +616,7 @@
                                    for iface in ifaces)
                 if not ('Any' in ifaces or ifaces & implemented_interfaces):
                     self.debug('unregister %s (no implemented '
-                               'interface among %s)', obj, ifaces)
+                               'interface among %s)', classid(obj), ifaces)
                     self.unregister(obj)
             # since 3.9: remove appobjects which depending on other, unexistant
             # appobjects
@@ -625,7 +624,8 @@
                 try:
                     registry = self[regname]
                 except RegistryNotFound:
-                    self.debug('unregister %s (no registry %s)', obj, regname)
+                    self.debug('unregister %s (no registry %s)', classid(obj),
+                               regname)
                     self.unregister(obj)
                     continue
                 for regid in regids:
@@ -633,7 +633,7 @@
                         break
                 else:
                     self.debug('unregister %s (no %s object in registry %s)',
-                               obj, ' or '.join(regids), regname)
+                               classid(obj), ' or '.join(regids), regname)
                     self.unregister(obj)
         super(CubicWebVRegistry, self).initialization_completed()
         for rtag in RTAGS:
--- a/devtools/cwwindmill.py	Fri Jul 30 10:09:31 2010 +0200
+++ b/devtools/cwwindmill.py	Fri Jul 30 13:18:36 2010 +0200
@@ -92,6 +92,8 @@
             # see windmill.bin.admin_options.Firebug
             import windmill
             windmill.settings['INSTALL_FIREBUG'] = 'firebug'
+            windmill.settings['MOZILLA_PLUGINS'].append('/usr/share/mozilla-extensions/')
+            windmill.settings['MOZILLA_PLUGINS'].append('/usr/share/xul-ext/')
 
         self.windmill_shell_objects['start_' + self.browser]()
         self.windmill_shell_objects['do_test'](self.test_dir,
--- a/migration.py	Fri Jul 30 10:09:31 2010 +0200
+++ b/migration.py	Fri Jul 30 13:18:36 2010 +0200
@@ -24,13 +24,15 @@
 import logging
 import tempfile
 from os.path import exists, join, basename, splitext
+from itertools import chain
 
+from logilab.common import IGNORED_EXTENSIONS
 from logilab.common.decorators import cached
 from logilab.common.configuration import REQUIRED, read_old_config
 from logilab.common.shellutils import ASK
 from logilab.common.changelog import Version
 
-from cubicweb import ConfigurationError
+from cubicweb import ConfigurationError, ExecutionError
 
 
 def filter_scripts(config, directory, fromversion, toversion, quiet=True):
@@ -51,8 +53,7 @@
         return []
     result = []
     for fname in os.listdir(directory):
-        if fname.endswith('.pyc') or fname.endswith('.pyo') \
-               or fname.endswith('~'):
+        if fname.endswith(IGNORED_EXTENSIONS):
             continue
         fpath = join(directory, fname)
         try:
@@ -75,9 +76,6 @@
     return sorted(result)
 
 
-IGNORED_EXTENSIONS = ('.swp', '~')
-
-
 def execscript_confirm(scriptpath):
     """asks for confirmation before executing a script and provides the
     ability to show the script's content
@@ -285,6 +283,16 @@
         Display the migration script path, ask for confirmation and execute it
         if confirmed
 
+        Allowed input file formats for migration scripts:
+        - `python` (.py)
+        - `sql` (.sql)
+        - `doctest` (.txt or .rst)
+
+        .. warning:: sql migration scripts are not available in web-only instance
+
+        You can pass script parameters with using double dash (--) in the
+        command line
+
         Context environment can have these variables defined:
         - __name__ : will be determine by funcname parameter
         - __file__ : is the name of the script if it exists
@@ -295,13 +303,20 @@
         :params args: optional arguments for funcname
         :keyword scriptargs: optional arguments of the script
         """
+        ftypes = {'python':  ('.py',),
+                  'doctest': ('.txt', '.rst'),
+                  'sql':     ('.sql',)}
+        # sql migration scripts are not available in web-only instance
+        if not hasattr(self, "session"):
+            ftypes.pop('sql')
         migrscript = os.path.normpath(migrscript)
-        if migrscript.endswith('.py'):
-            script_mode = 'python'
-        elif migrscript.endswith(('.txt', '.rst')):
-            script_mode = 'doctest'
+        for (script_mode, ftype) in ftypes.items():
+            if migrscript.endswith(ftype):
+                break
         else:
-            raise Exception('This is not a valid cubicweb shell input')
+            ftypes = ', '.join(chain(*ftypes.values()))
+            msg = 'ignoring %s, not a valid script extension (%s)'
+            raise ExecutionError(msg % (migrscript, ftypes))
         if not self.execscript_confirm(migrscript):
             return
         scriptlocals = self._create_context().copy()
@@ -322,6 +337,10 @@
                     self.critical('no %s in script %s', funcname, migrscript)
                     return None
                 return func(*args, **kwargs)
+        elif script_mode == 'sql':
+            from cubicweb.server.sqlutils import sqlexec
+            sqlexec(open(migrscript).read(), self.session.system_sql)
+            self.commit()
         else: # script_mode == 'doctest'
             import doctest
             doctest.testfile(migrscript, module_relative=False,
--- a/selectors.py	Fri Jul 30 10:09:31 2010 +0200
+++ b/selectors.py	Fri Jul 30 13:18:36 2010 +0200
@@ -212,24 +212,24 @@
 
 from cubicweb.appobject import traced_selection # XXX for bw compat
 
-def score_interface(etypesreg, cls_or_inst, cls, iface):
+def score_interface(etypesreg, eclass, iface):
     """Return XXX if the give object (maybe an instance or class) implements
     the interface.
     """
     if getattr(iface, '__registry__', None) == 'etypes':
         # adjust score if the interface is an entity class
-        parents = etypesreg.parent_classes(cls_or_inst.__regid__)
-        if iface is cls:
+        parents, any = etypesreg.parent_classes(eclass.__regid__)
+        if iface is eclass:
             return len(parents) + 4
-        if iface is parents[-1]: # Any
+        if iface is any: # Any
             return 1
-        for index, basecls in enumerate(reversed(parents[:-1])):
+        for index, basecls in enumerate(reversed(parents)):
             if iface is basecls:
                 return index + 3
         return 0
     # XXX iface in implements deprecated in 3.9
-    if implements_iface(cls_or_inst, iface):
-        # implenting an interface takes precedence other special Any interface
+    if implements_iface(eclass, iface):
+        # implementing an interface takes precedence other special Any interface
         return 2
     return 0
 
@@ -699,9 +699,6 @@
                            ','.join(str(s) for s in self.expected_ifaces))
 
     def score_class(self, eclass, req):
-        return self.score_interfaces(req, eclass, eclass)
-
-    def score_interfaces(self, req, cls_or_inst, cls):
         score = 0
         etypesreg = req.vreg['etypes']
         for iface in self.expected_ifaces:
@@ -711,7 +708,7 @@
                     iface = etypesreg.etype_class(iface)
                 except KeyError:
                     continue # entity type not in the schema
-            score += score_interface(etypesreg, cls_or_inst, cls, iface)
+            score += score_interface(etypesreg, eclass, iface)
         return score
 
 def _reset_is_instance_cache(vreg):
@@ -744,9 +741,6 @@
                            ','.join(str(s) for s in self.expected_etypes))
 
     def score_class(self, eclass, req):
-        return self.score_etypes(req, eclass, eclass)
-
-    def score_etypes(self, req, cls_or_inst, cls):
         # cache on vreg to avoid reloading issues
         cache = req.vreg._is_instance_selector_cache
         try:
@@ -758,22 +752,20 @@
             expected_eclasses = cache[self] = []
             for etype in self.expected_etypes:
                 try:
-                    expected_eclasses.append(
-                        (etypesreg.etype_class(etype),
-                         etypesreg.parent_classes(etype))
-                        )
+                    expected_eclasses.append(etypesreg.etype_class(etype))
                 except KeyError:
                     continue # entity type not in the schema
+        parents, any = req.vreg['etypes'].parent_classes(eclass.__regid__)
         score = 0
-        for iface, parents in expected_eclasses:
+        for expectedcls in expected_eclasses:
             # adjust score according to class proximity
-            if iface is cls:
+            if expectedcls is eclass:
                 score += len(parents) + 4
-            elif iface is parents[-1]: # Any
+            elif expectedcls is any: # Any
                 score += 1
             else:
-                for index, basecls in enumerate(reversed(parents[:-1])):
-                    if iface is basecls:
+                for index, basecls in enumerate(reversed(parents)):
+                    if expectedcls is basecls:
                         score += index + 3
                         break
         return score
--- a/server/migractions.py	Fri Jul 30 10:09:31 2010 +0200
+++ b/server/migractions.py	Fri Jul 30 13:18:36 2010 +0200
@@ -49,7 +49,7 @@
 from yams.constraints import SizeConstraint
 from yams.schema2sql import eschema2sql, rschema2sql
 
-from cubicweb import AuthenticationError
+from cubicweb import AuthenticationError, ExecutionError
 from cubicweb.schema import (ETYPE_NAME_MAP, META_RTYPES, VIRTUAL_RTYPES,
                              PURE_VIRTUAL_RTYPES,
                              CubicWebRelationSchema, order_eschemas)
@@ -117,27 +117,18 @@
             super(ServerMigrationHelper, self).migrate(vcconf, toupgrade, options)
 
     def cmd_process_script(self, migrscript, funcname=None, *args, **kwargs):
-        """execute a migration script
-        in interactive mode,  display the migration script path, ask for
-        confirmation and execute it if confirmed
-        """
         try:
-            if migrscript.endswith('.sql'):
-                if self.execscript_confirm(migrscript):
-                    sqlexec(open(migrscript).read(), self.session.system_sql)
-            elif migrscript.endswith('.py') or migrscript.endswith('.txt'):
-                return super(ServerMigrationHelper, self).cmd_process_script(
-                    migrscript, funcname, *args, **kwargs)
-            else:
-                print >> sys.stderr
-                print >> sys.stderr, ('-> ignoring %s, only .py .sql and .txt scripts are considered' %
-                       migrscript)
-                print >> sys.stderr
-            self.commit()
+            return super(ServerMigrationHelper, self).cmd_process_script(
+                  migrscript, funcname, *args, **kwargs)
+        except ExecutionError, err:
+            print >> sys.stderr, "-> %s" % err
         except:
             self.rollback()
             raise
 
+    # Adjust docstring
+    cmd_process_script.__doc__ = MigrationHelper.cmd_process_script.__doc__
+
     # server specific migration methods ########################################
 
     def backup_database(self, backupfile=None, askconfirm=True):
--- a/test/unittest_selectors.py	Fri Jul 30 10:09:31 2010 +0200
+++ b/test/unittest_selectors.py	Fri Jul 30 13:18:36 2010 +0200
@@ -151,6 +151,11 @@
         cls = self.vreg['etypes'].etype_class('Personne')
         self.failIf(is_instance('Societe').score_class(cls, self.request()))
 
+    def test_yams_inheritance(self):
+        cls = self.vreg['etypes'].etype_class('Transition')
+        self.assertEquals(is_instance('BaseTransition').score_class(cls, self.request()),
+                          3)
+
 
 class MatchUserGroupsTC(CubicWebTC):
     def test_owners_group(self):
--- a/utils.py	Fri Jul 30 10:09:31 2010 +0200
+++ b/utils.py	Fri Jul 30 13:18:36 2010 +0200
@@ -15,9 +15,8 @@
 #
 # You should have received a copy of the GNU Lesser General Public License along
 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
-"""Some utilities for CubicWeb server/clients.
+"""Some utilities for CubicWeb server/clients."""
 
-"""
 __docformat__ = "restructuredtext en"
 
 import os
--- a/view.py	Fri Jul 30 10:09:31 2010 +0200
+++ b/view.py	Fri Jul 30 13:18:36 2010 +0200
@@ -23,7 +23,6 @@
 from cStringIO import StringIO
 from warnings import warn
 
-from cubicweb.utils import json
 from logilab.common.deprecation import deprecated
 from logilab.mtconverter import xml_escape
 
@@ -33,6 +32,7 @@
 from cubicweb.selectors import yes, non_final_entity, nonempty_rset, none_rset
 from cubicweb.appobject import AppObject
 from cubicweb.utils import UStringIO, HTMLStream
+from cubicweb.uilib import domid, js
 from cubicweb.schema import display_name
 from cubicweb.vregistry import classid
 
@@ -325,7 +325,8 @@
         return self._cw.vreg["etypes"].etype_class(etype).cw_create_url(
             self._cw, **kwargs)
 
-    def field(self, label, value, row=True, show_label=True, w=None, tr=True, table=False):
+    def field(self, label, value, row=True, show_label=True, w=None, tr=True,
+              table=False):
         """read-only field"""
         if w is None:
             w = self.w
@@ -495,12 +496,11 @@
 
     def build_update_js_call(self, cbname, msg):
         rql = self.cw_rset.printable_rql()
-        return "javascript:userCallbackThenUpdateUI('%s', '%s', %s, %s, '%s', '%s')" % (
-            cbname, self.id, json.dumps(rql), json.dumps(msg),
-            self.__registry__, self.div_id())
+        return "javascript: %s" % js.userCallbackThenUpdateUI(
+            cbname, self.__regid__, rql, msg, self.__registry__, self.domid)
 
     def build_reload_js_call(self, cbname, msg):
-        return "javascript:userCallbackThenReloadPage('%s', %s)" % (cbname, json.dumps(msg))
+        return "javascript: %s" % js.userCallbackThenReloadPage(cbname, msg)
 
     build_js = build_update_js_call # expect updatable component by default
 
--- a/web/data/cubicweb.edition.js	Fri Jul 30 10:09:31 2010 +0200
+++ b/web/data/cubicweb.edition.js	Fri Jul 30 13:18:36 2010 +0200
@@ -586,7 +586,7 @@
     try {
         var zipped = cw.utils.formContents(formid);
         var args = ajaxFuncArgs('validate_form', null, action, zipped[0], zipped[1]);
-        var d = loadRemote('json', args);
+        var d = loadRemote('json', args, 'POST');
     } catch(ex) {
         log('got exception', ex);
         return false;
--- a/web/facet.py	Fri Jul 30 10:09:31 2010 +0200
+++ b/web/facet.py	Fri Jul 30 13:18:36 2010 +0200
@@ -271,13 +271,14 @@
     __registry__ = 'facets'
     cw_property_defs = {
         _('visible'): dict(type='Boolean', default=True,
-                           help=_('display the box or not')),
+                           help=_('display the facet or not')),
         _('order'):   dict(type='Int', default=99,
-                           help=_('display order of the box')),
+                           help=_('display order of the facet')),
         _('context'): dict(type='String', default='',
                            # None <-> both
                            vocabulary=(_('tablefilter'), _('facetbox'), ''),
-                           help=_('context where this box should be displayed')),
+                           help=_('context where this facet should be displayed, '
+                                  'leave empty for both')),
         }
     visible = True
     context = ''
--- a/web/test/windmill/test_connexion.py	Fri Jul 30 10:09:31 2010 +0200
+++ b/web/test/windmill/test_connexion.py	Fri Jul 30 13:18:36 2010 +0200
@@ -9,16 +9,21 @@
     client = WindmillTestClient(__name__)
 
     client.open(url=u'/')
+    client.waits.forPageLoad(timeout=u'20000')
     client.asserts.assertJS(js=u"$('#loginForm').is(':visible')")
     client.type(text=LOGIN, id=u'__login')
     client.type(text=PASSWORD, id=u'__password')
+
     client.execJS(js=u"$('#loginForm').submit()")
     client.waits.forPageLoad(timeout=u'20000')
     client.asserts.assertJS(js=u'$(\'.message\').text() == "welcome %s !"' % LOGIN)
     client.open(url=u'/logout')
+    client.waits.forPageLoad(timeout=u'20000')
     client.open(url=u'/')
+    client.waits.forPageLoad(timeout=u'20000')
     client.asserts.assertJS(js=u"$('#loginForm').is(':visible')")
 
+
 def test_wrong_connect():
     client = WindmillTestClient(__name__)
 
@@ -32,4 +37,5 @@
     client.waits.forPageLoad(timeout=u'20000')
     client.asserts.assertTextIn(validator=u'authentication failure', id=u'loginBox')
     client.open(url=u'/')
+    client.waits.forPageLoad(timeout=u'20000')
     client.asserts.assertJS(js=u"$('#loginForm').is(':visible')")
--- a/web/views/schema.py	Fri Jul 30 10:09:31 2010 +0200
+++ b/web/views/schema.py	Fri Jul 30 13:18:36 2010 +0200
@@ -304,7 +304,7 @@
         _ = self._cw._
         # inheritance
         if entity.specializes:
-            self.w(u'<div>%s' % _('Parent classes:'))
+            self.w(u'<div>%s' % _('Parent class:'))
             self.wview('csv', entity.related('specializes', 'subject'))
             self.w(u'</div>')
         if entity.reverse_specializes: