[vreg] vregistry._select_best was needlessly instanciating NoSelectableObject (closes #1626708)
authorAlexandre Fayolle <alexandre.fayolle@logilab.fr>
Wed, 27 Apr 2011 16:38:01 +0200
changeset 7272 771f594c12a2
parent 7271 2bd70418b601
child 7278 1144a2d90314
[vreg] vregistry._select_best was needlessly instanciating NoSelectableObject (closes #1626708) in large selections, this incurred a non negligible cost (add_relations with 2000 inlined relations runs 7% faster with this patch)
cwvreg.py
devtools/testlib.py
vregistry.py
web/views/urlpublishing.py
--- a/cwvreg.py	Thu Apr 28 15:30:16 2011 +0200
+++ b/cwvreg.py	Wed Apr 27 16:38:01 2011 +0200
@@ -402,10 +402,8 @@
                      if not isinstance(view, class_deprecated)]
             try:
                 view = self._select_best(views, req, rset=rset, **kwargs)
-                if view.linkable():
+                if view is not None and view.linkable():
                     yield view
-            except NoSelectableObject:
-                continue
             except Exception:
                 self.exception('error while trying to select %s view for %s',
                                vid, rset)
--- a/devtools/testlib.py	Thu Apr 28 15:30:16 2011 +0200
+++ b/devtools/testlib.py	Wed Apr 27 16:38:01 2011 +0200
@@ -562,6 +562,8 @@
             if views:
                 try:
                     view = viewsvreg._select_best(views, req, rset=rset)
+                    if view is None:
+                        raise NoSelectableObject((req,), {'rset':rset}, views)
                     if view.linkable():
                         yield view
                     else:
--- a/vregistry.py	Thu Apr 28 15:30:16 2011 +0200
+++ b/vregistry.py	Wed Apr 27 16:38:01 2011 +0200
@@ -184,7 +184,10 @@
 
         raise :exc:`NoSelectableObject` if not object apply
         """
-        return self._select_best(self[__oid], *args, **kwargs)
+        obj =  self._select_best(self[__oid], *args, **kwargs)
+        if obj is None:
+            raise NoSelectableObject(args, kwargs, self[__oid] )
+        return obj
 
     def select_or_none(self, __oid, *args, **kwargs):
         """return the most specific object among those with the given oid
@@ -202,16 +205,18 @@
         context
         """
         for appobjects in self.itervalues():
-            try:
-                yield self._select_best(appobjects, *args, **kwargs)
-            except NoSelectableObject:
+            obj = self._select_best(appobjects,  *args, **kwargs)
+            if obj is None:
                 continue
+            yield obj
 
     def _select_best(self, appobjects, *args, **kwargs):
         """return an instance of the most specific object according
         to parameters
 
-        raise `NoSelectableObject` if not object apply
+        return None if not object apply (don't raise `NoSelectableObject` since
+        it's costly when searching appobjects using `possible_objects`
+        (e.g. searching for hooks).
         """
         if len(args) > 1:
             warn('[3.5] only the request param can not be named when calling select*',
@@ -224,7 +229,7 @@
             elif appobjectscore > 0 and appobjectscore == score:
                 winners.append(appobject)
         if winners is None:
-            raise NoSelectableObject(args, kwargs, appobjects)
+            return None
         if len(winners) > 1:
             # log in production environement / test, error while debugging
             msg = 'select ambiguity: %s\n(args: %s, kwargs: %s)'
--- a/web/views/urlpublishing.py	Thu Apr 28 15:30:16 2011 +0200
+++ b/web/views/urlpublishing.py	Wed Apr 27 16:38:01 2011 +0200
@@ -260,9 +260,8 @@
             else:
                 try:
                     action = actionsreg._select_best(actions, req, rset=rset)
+                    if action is not None:
+                        raise Redirect(action.url())
                 except RegistryException:
-                    continue
-                else:
-                    # XXX avoid redirect
-                    raise Redirect(action.url())
+                    pass # continue searching
         raise PathDontMatch()