[Zope3-checkins] SVN: Zope3/branches/ZopeX3-3.0/src/zope/interface/ Merge patch by Gustavo Niemeyer to return the best match for a multi-adapter, which got checked in only on trunk

Sidnei da Silva sidnei at awkly.org
Wed Oct 20 22:31:02 EDT 2004


Log message for revision 28224:
  Merge patch by Gustavo Niemeyer to return the best match for a multi-adapter, which got checked in only on trunk

Changed:
  U   Zope3/branches/ZopeX3-3.0/src/zope/interface/adapter.py
  U   Zope3/branches/ZopeX3-3.0/src/zope/interface/tests/test_adapter.py

-=-
Modified: Zope3/branches/ZopeX3-3.0/src/zope/interface/adapter.py
===================================================================
--- Zope3/branches/ZopeX3-3.0/src/zope/interface/adapter.py	2004-10-21 01:20:02 UTC (rev 28223)
+++ Zope3/branches/ZopeX3-3.0/src/zope/interface/adapter.py	2004-10-21 02:31:02 UTC (rev 28224)
@@ -352,12 +352,30 @@
             if not bywith:
                 continue
 
+            # Selecting multi-adapters is not just a matter of matching the
+            # required interfaces of the adapter to the ones passed. Several
+            # adapters might match, but we only want the best one. We use a
+            # ranking algorithm to determine the best match.
+
+            # `best` carries the rank and value of the best found adapter.
+            best = None
             for rwith, value in bywith:
+                # the `rank` describes how well the found adapter matches.
+                rank = []
                 for rspec, spec in zip(rwith, with):
                     if not spec.isOrExtends(rspec):
                         break # This one is no good
+                    # Determine the rank of this particular specification.
+                    rank.append(list(spec.__sro__).index(rspec))
                 else:
-                    return value
+                    # If the new rank is better than the best previously
+                    # recorded one, make the new adapter the best one found. 
+                    rank = tuple(rank)
+                    if best is None or rank < best[0]:
+                        best = rank, value
+            # If any match was found, return the best one.
+            if best:
+                return best[1]
 
         return default
 

Modified: Zope3/branches/ZopeX3-3.0/src/zope/interface/tests/test_adapter.py
===================================================================
--- Zope3/branches/ZopeX3-3.0/src/zope/interface/tests/test_adapter.py	2004-10-21 01:20:02 UTC (rev 28223)
+++ Zope3/branches/ZopeX3-3.0/src/zope/interface/tests/test_adapter.py	2004-10-21 02:31:02 UTC (rev 28224)
@@ -35,6 +35,51 @@
 class IR1(IR0):
     pass
 
+
+def test_orderwith():
+    """
+    >>> Interface = zope.interface.Interface
+    >>> bywith = {(Interface, Interface): 'A0',
+    ...           (IF0,       Interface): 'A1', 
+    ...           (Interface, IB0):       'A2', 
+    ...           (IF0,       IB0):       'A3', 
+    ...           (IF1,       IB0):       'A4', 
+    ...           (IF0,       IB1):       'A5', 
+    ...           (IF1,       IB1):       'A6', 
+    ...          }
+
+    >>> [value for spec, value in zope.interface.adapter.orderwith(bywith)]
+    ['A6', 'A4', 'A5', 'A3', 'A1', 'A2', 'A0']
+    """
+
+
+def test_multi_adapter_get_best_match():
+    """
+    >>> registry = AdapterRegistry()
+
+    >>> class IB2(IB0):
+    ...     pass
+    >>> class IB3(IB2, IB1):
+    ...     pass
+    >>> class IB4(IB1, IB2):
+    ...     pass
+
+    >>> registry.register([None, IB1], IR0, '', 'A1')
+    >>> registry.register([None, IB0], IR0, '', 'A0')
+    >>> registry.register([None, IB2], IR0, '', 'A2')
+
+    >>> registry.lookup((IF1, IB1), IR0, '')
+    'A1'
+    >>> registry.lookup((IF1, IB2), IR0, '')
+    'A2'
+    >>> registry.lookup((IF1, IB0), IR0, '')
+    'A0'
+    >>> registry.lookup((IF1, IB3), IR0, '')
+    'A2'
+    >>> registry.lookup((IF1, IB4), IR0, '')
+    'A1'
+    """
+
 def test_multi_adapter_w_default():
     """
     >>> registry = AdapterRegistry()
@@ -141,4 +186,5 @@
         doctest.DocTestSuite(),
         ))
 
-if __name__ == '__main__': unittest.main()
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')



More information about the Zope3-Checkins mailing list