[Zope3-checkins] SVN: Zope3/branches/jim-adapter-redesign/ First cut at adapter-registry refactoring. The refactoring makes

Jim Fulton jim at zope.com
Thu Sep 8 06:17:23 EDT 2005


Log message for revision 38384:
  First cut at adapter-registry refactoring.  The refactoring makes
  adapter lookup work more like method lookup.  This provides:
  
  - a much simpler algorithm,
  
  - a basis for super-like adapter lookup, and
  
  - a fix for a bug in multi-adapter lookup.
  
  These changes also remove the distinction between objects with no
  interface declarations and objects that declare that they provide
  Interface.
  
  Unfortunately, these version is *much* too slow.  I'm checking this
  version in to save it before trying some variations.
  

Changed:
  U   Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/component.py
  U   Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/component.txt
  U   Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/ifacemodule/browser.txt
  U   Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/presentation.txt
  U   Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/tests.py
  U   Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/utilities.py
  U   Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/utilities.txt
  U   Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/utilitymodule/browser.txt
  U   Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/zcmlmodule/browser.txt
  U   Zope3/branches/jim-adapter-redesign/src/zope/app/authentication/browser/principalfolder.txt
  U   Zope3/branches/jim-adapter-redesign/src/zope/app/component/adapter.py
  U   Zope3/branches/jim-adapter-redesign/src/zope/app/component/interfaces/__init__.py
  U   Zope3/branches/jim-adapter-redesign/src/zope/app/component/site.py
  U   Zope3/branches/jim-adapter-redesign/src/zope/app/component/tests/test_adapter.py
  U   Zope3/branches/jim-adapter-redesign/src/zope/app/component/tests/test_directives.py
  U   Zope3/branches/jim-adapter-redesign/src/zope/app/debugskin/configure.zcml
  U   Zope3/branches/jim-adapter-redesign/src/zope/app/form/browser/configure.zcml
  U   Zope3/branches/jim-adapter-redesign/src/zope/app/locking/tests.py
  U   Zope3/branches/jim-adapter-redesign/src/zope/app/module/README.txt
  U   Zope3/branches/jim-adapter-redesign/src/zope/app/pagetemplate/configure.zcml
  U   Zope3/branches/jim-adapter-redesign/src/zope/app/publication/traversers.py
  U   Zope3/branches/jim-adapter-redesign/src/zope/app/traversing/browser/configure.zcml
  U   Zope3/branches/jim-adapter-redesign/src/zope/component/site.py
  U   Zope3/branches/jim-adapter-redesign/src/zope/interface/_zope_interface_coptimizations.c
  U   Zope3/branches/jim-adapter-redesign/src/zope/interface/adapter.py
  U   Zope3/branches/jim-adapter-redesign/src/zope/interface/adapter.txt
  U   Zope3/branches/jim-adapter-redesign/src/zope/interface/declarations.py
  U   Zope3/branches/jim-adapter-redesign/src/zope/interface/interface.py
  U   Zope3/branches/jim-adapter-redesign/src/zope/interface/interfaces.py
  U   Zope3/branches/jim-adapter-redesign/src/zope/interface/tests/test_adapter.py
  U   Zope3/branches/jim-adapter-redesign/src/zope/security/checker.py
  U   Zope3/branches/jim-adapter-redesign/z3.py

-=-
Modified: Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/component.py
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/component.py	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/component.py	2005-09-08 10:17:23 UTC (rev 38384)
@@ -59,14 +59,16 @@
     gsm = zapi.getGlobalSiteManager()
     for reg in gsm.registrations():
         # Only get adapters
-        if not isinstance(reg, (AdapterRegistration, SubscriptionRegistration)):
+        if not isinstance(reg,
+                          (AdapterRegistration, SubscriptionRegistration)):
             continue
         # Ignore adapters that have no required interfaces
         if len(reg.required) == 0:
             continue
         # Ignore views
-        if not withViews and reg.required[-1] and \
-               reg.required[-1].isOrExtends(IRequest):
+        if (not withViews and reg.required[-1]
+            and reg.required[-1].isOrExtends(IRequest)
+            ):
             continue
         # Only get adapters for which this interface is provided
         if reg.provided is None or not reg.provided.isOrExtends(iface):
@@ -172,6 +174,11 @@
        url = None
     else:
         url = path.replace('.', '/')
+
+    if ' ' in url:
+        # We got a generated class. It can't have a url
+        url = None
+                
     if isinstance(reg.doc, (str, unicode)):
         doc = reg.doc
         zcml = None

Modified: Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/component.txt
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/component.txt	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/component.txt	2005-09-08 10:17:23 UTC (rev 38384)
@@ -241,8 +241,8 @@
 
   >>> pprint(component.getAdapterInfoDictionary(reg))
   {'doc': 'doc info',
-   'factory': '__builtin__.MyResult',
-   'factory_url': '__builtin__/MyResult',
+   'factory': '__builtin__.MyResult ?',
+   'factory_url': None,
    'name': 'FooToResult',
    'provided': {'module': '__builtin__', 'name': 'IResult'},
    'required': [{'module': '__builtin__', 'name': 'IFoo'},
@@ -258,8 +258,8 @@
 
   >>> pprint(component.getAdapterInfoDictionary(reg))
   {'doc': 'doc info',
-   'factory': '__builtin__.MyResult',
-   'factory_url': '__builtin__/MyResult',
+   'factory': '__builtin__.MyResult ?',
+   'factory_url': None,
    'name': u'<subscription>',
    'provided': None,
    'required': [{'module': '__builtin__', 'name': 'IFoo'},
@@ -281,7 +281,7 @@
   {'description': u'<p>My Foo Bar</p>\n',
    'name': 'MyFooBar',
    'title': 'MyFooBar',
-   'url': '__builtin__/MyFooBar'}
+   'url': '__builtin__/MyFooBar ?'}
 
 
 `getUtilityInfoDictionary(name, factory)`
@@ -296,6 +296,6 @@
   >>> pprint(component.getUtilityInfoDictionary(
   ...     component.getUtilities(IFooBar).next()))
   {'name': u'<i>no name</i>',
-   'path': '__builtin__.MyFooBar',
-   'url': '__builtin__/MyFooBar',
+   'path': '__builtin__.MyFooBar ?',
+   'url': '__builtin__/MyFooBar ?',
    'url_name': '__noname__'}

Modified: Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/ifacemodule/browser.txt
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/ifacemodule/browser.txt	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/ifacemodule/browser.txt	2005-09-08 10:17:23 UTC (rev 38384)
@@ -218,9 +218,12 @@
 
   >>> pprint(details.getTypes())
   [{'name': 'IMyType',
-    'path': '__builtin__.IMyType'}]
+    'path': '__builtin__.IMyType ?'}]
 
+Note that a space and question mark is shown after the object name to
+indicate that the object name wasn't found in the module.
 
+
 `getAttributes()`
 -----------------
 
@@ -300,8 +303,96 @@
 Get adapters where this interface is required.
 
   >>> pprint(details.getGenericRequiredAdapters())
-  []
+  [{'doc': '',
+    'factory': 'append',
+    'factory_url': 'append',
+    'name': u'<subscription>',
+    'provided': None,
+    'required': [{'module': 'zope.interface',
+                  'name': 'Interface'}],
+    'zcml': None},
+   {'doc': '',
+    'factory': 'zope.app.traversing.adapters.Traverser',
+    'factory_url': 'zope/app/traversing/adapters/Traverser',
+    'name': '',
+    'provided': {'module': 'zope.app.traversing.interfaces',
+                 'name': 'ITraverser'},
+    'required': [{'module': 'zope.interface',
+                  'name': 'Interface'}],
+    'zcml': None},
+   {'doc': '',
+    'factory': 'zope.app.traversing.adapters.DefaultTraversable',
+    'factory_url': 'zope/app/traversing/adapters/DefaultTraversable',
+    'name': '',
+    'provided': {'module': 'zope.app.traversing.interfaces',
+                 'name': 'ITraversable'},
+    'required': [{'module': 'zope.interface',
+                  'name': 'Interface'}],
+    'zcml': None},
+   {'doc': '',
+    'factory': 'zope.app.location.traversing.LocationPhysicallyLocatable',
+    'factory_url': 'zope/app/location/traversing/LocationPhysicallyLocatable',
+    'name': '',
+    'provided': {'module': 'zope.app.traversing.interfaces',
+                 'name': 'IPhysicallyLocatable'},
+    'required': [{'module': 'zope.interface',
+                  'name': 'Interface'}],
+    'zcml': None},
+   {'doc': '',
+    'factory': 'zope.app.traversing.namespace.etc',
+    'factory_url': 'zope/app/traversing/namespace/etc',
+    'name': 'etc',
+    'provided': {'module': 'zope.app.traversing.interfaces',
+                 'name': 'ITraversable'},
+    'required': [{'module': 'zope.interface',
+                  'name': 'Interface'}],
+    'zcml': None},
+   {'doc': '',
+    'factory': 'zope.app.traversing.namespace.etc',
+    'factory_url': 'zope/app/traversing/namespace/etc',
+    'name': 'etc',
+    'provided': {'module': 'zope.app.traversing.interfaces',
+                 'name': 'ITraversable'},
+    'required': [{'module': 'zope.interface',
+                  'name': 'Interface'},
+                 {'module': 'zope.interface',
+                  'name': 'Interface'}],
+    'zcml': None},
+   {'doc': '',
+    'factory': 'zope.app.traversing.namespace.etc',
+    'factory_url': 'zope/app/traversing/namespace/etc',
+    'name': 'etc',
+    'provided': {'module': 'zope.app.traversing.interfaces',
+                 'name': 'ITraversable'},
+    'required': [{'module': 'zope.interface',
+                  'name': 'Interface'},
+                 {'module': 'zope.interface',
+                  'name': 'Interface'}],
+    'zcml': None},
+   {'doc': '',
+    'factory': 'zope.app.traversing.namespace.etc',
+    'factory_url': 'zope/app/traversing/namespace/etc',
+    'name': 'etc',
+    'provided': {'module': 'zope.app.traversing.interfaces',
+                 'name': 'ITraversable'},
+    'required': [{'module': 'zope.interface',
+                  'name': 'Interface'},
+                 {'module': 'zope.interface',
+                  'name': 'Interface'}],
+    'zcml': None},
+   {'doc': '',
+    'factory': 'zope.app.traversing.namespace.etc',
+    'factory_url': 'zope/app/traversing/namespace/etc',
+    'name': 'etc',
+    'provided': {'module': 'zope.app.traversing.interfaces',
+                 'name': 'ITraversable'},
+    'required': [{'module': 'zope.interface',
+                  'name': 'Interface'},
+                 {'module': 'zope.interface',
+                  'name': 'Interface'}],
+    'zcml': None}]
 
+Note that these include interfaces for which *any* interface is required.
 
 `getProvidedAdapters()`
 -----------------------
@@ -310,8 +401,8 @@
 
   >>> pprint(details.getProvidedAdapters())
   [{'doc': '',
-    'factory': '__builtin__.Foo',
-    'factory_url': '__builtin__/Foo',
+    'factory': '__builtin__.Foo ?',
+    'factory_url': None,
     'name': '',
     'provided': {'module': '__builtin__',
                  'name': 'IFoo'},
@@ -319,6 +410,8 @@
                   'name': 'IBar'}],
     'zcml': None}]
 
+Note that the factory URL is None, because the factory doesn't
+actually exist in __builtin__.
 
 `getClasses()`
 ---------------
@@ -339,7 +432,7 @@
   [{'description': u'',
     'name': 'FooFactory',
     'title': 'Foo Factory',
-    'url': '__builtin__/Foo'}]
+    'url': '__builtin__/Foo ?'}]
 
 `getUtilities()`
 ----------------
@@ -348,6 +441,6 @@
 
   >>> pprint(details.getUtilities())
   [{'name': 'The Foo',
-    'path': '__builtin__.Foo',
-    'url': '__builtin__/Foo',
-    'url_name': 'The Foo'}]
\ No newline at end of file
+    'path': '__builtin__.Foo ?',
+    'url': '__builtin__/Foo ?',
+    'url_name': 'The Foo'}]

Modified: Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/presentation.txt
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/presentation.txt	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/presentation.txt	2005-09-08 10:17:23 UTC (rev 38384)
@@ -62,22 +62,22 @@
   
   >>> info = presentation.getViewFactoryData(Factory())
   >>> pprint(info)
-  {'path': '__builtin__.Factory',
+  {'path': '__builtin__.Factory ?',
    'referencable': True,
    'resource': None,
    'template': None,
-   'url': '__builtin__/Factory'}
+   'url': '__builtin__/Factory ?'}
 
 One of the more common cases, however, is that the factory is a class or
 type. In this case we can just retrieve the reference directly: 
 
   >>> info = presentation.getViewFactoryData(Factory)
   >>> pprint(info)
-  {'path': '__builtin__.Factory',
+  {'path': '__builtin__.Factory ?',
    'referencable': True,
    'resource': None,
    'template': None,
-   'url': '__builtin__/Factory'}
+   'url': '__builtin__/Factory ?'}
  
 When factories are created by the directive, they can also be functions. In
 those cases we just simply return the function path:
@@ -90,11 +90,11 @@
 
   >>> info = presentation.getViewFactoryData(factory)
   >>> pprint(info)
-  {'path': '__builtin__.factory',
+  {'path': '__builtin__.factory ?',
    'referencable': True,
    'resource': None,
    'template': None,
-   'url': '__builtin__/factory'}
+   'url': '__builtin__/factory ?'}
 
 However, the function is rather unhelpful, since it will be the same for all
 views that use that code path. For this reason the function keeps track of the
@@ -104,11 +104,11 @@
 
   >>> info = presentation.getViewFactoryData(factory)
   >>> pprint(info)
-  {'path': '__builtin__.Factory',
+  {'path': '__builtin__.Factory ?',
    'referencable': True,
    'resource': None,
    'template': None,
-   'url': '__builtin__/Factory'} 
+   'url': '__builtin__/Factory ?'} 
 
 
 `getPresentationType(iface)`
@@ -303,11 +303,11 @@
 
   >>> pprint(presentation.getViewInfoDictionary(reg))
   {'doc': 'reg info',
-   'factory': {'path': '__builtin__.Factory',
+   'factory': {'path': '__builtin__.Factory ?',
                'referencable': True,
                'resource': None,
                'template': None,
-               'url': '__builtin__/Factory'},
+               'url': '__builtin__/Factory ?'},
    'layer': None,
    'name': 'view.html',
    'provided': {'module': 'zope.interface',

Modified: Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/tests.py
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/tests.py	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/tests.py	2005-09-08 10:17:23 UTC (rev 38384)
@@ -18,6 +18,8 @@
 from pprint import PrettyPrinter
 import unittest
 
+import zope.component.testing
+
 from zope.component.interfaces import IFactory
 from zope.interface import implements
 from zope.testing import doctest, doctestunit
@@ -32,7 +34,7 @@
 
 
 def setUp(test):
-    placelesssetup.setUp()
+    zope.component.testing.setUp()
     # Register Renderer Components
     ztapi.provideUtility(IFactory, ReStructuredTextSourceFactory,
                          'zope.source.rest')    
@@ -80,8 +82,8 @@
                              globs={'pprint': doctestunit.pprint},
                              optionflags=doctest.NORMALIZE_WHITESPACE),
         doctest.DocFileSuite('presentation.txt',
-                             setUp=placelesssetup.setUp,
-                             tearDown=placelesssetup.tearDown,
+                             setUp=zope.component.testing.setUp,
+                             tearDown=zope.component.testing.tearDown,
                              globs={'pprint': doctestunit.pprint},
                              optionflags=doctest.NORMALIZE_WHITESPACE),
         doctest.DocFileSuite('utilities.txt',

Modified: Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/utilities.py
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/utilities.py	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/utilities.py	2005-09-08 10:17:23 UTC (rev 38384)
@@ -98,10 +98,17 @@
     if hasattr(naked, "im_class"):
         naked = naked.im_class
     module = getattr(naked, '__module__', _marker)
-    if module is _marker:
-        return naked.__name__
+    name = naked.__name__
+    if module is _marker or module is None:
+        return name
     else:
-        return '%s.%s' %(module, naked.__name__)
+        m = sys.modules.get(module)
+        if m is None:
+            module += ' ?'
+        else:
+            if m.__dict__.get(name) is not naked:
+                name += ' ?'
+        return '%s.%s' %(module, name)
 
 
 def _evalId(id):

Modified: Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/utilities.txt
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/utilities.txt	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/utilities.txt	2005-09-08 10:17:23 UTC (rev 38384)
@@ -164,7 +164,7 @@
   ...     pass
 
   >>> utilities.getPythonPath(ISample)
-  '__builtin__.ISample'
+  '__builtin__.ISample ?'
 
 and for classes
 
@@ -173,7 +173,7 @@
   ...         pass
 
   >>> utilities.getPythonPath(Sample.sample)
-  '__builtin__.Sample'
+  '__builtin__.Sample ?'
 
 One can also pass functions
 
@@ -182,12 +182,12 @@
 
   >>> # Result is a bit strange due to doctests
   >>> utilities.getPythonPath(sample)
-  'None.sample'
+  'sample'
 
 and even methods. If a method is passed in, its class path is returned.
 
   >>> utilities.getPythonPath(Sample.sample)
-  '__builtin__.Sample'
+  '__builtin__.Sample ?'
 
 Modules are another kind of objects that can return a python path:
 
@@ -471,7 +471,7 @@
 returned:
 
   >>> utilities.getInterfaceForAttribute('attr', (I1, I2))
-  '__builtin__.I1'
+  '__builtin__.I1 ?'
 
 If no match is found, ``None`` is returned.
 
@@ -571,4 +571,4 @@
 often safer (if available):
 
   >>> utilities.renderText('Hello!\n', module=apidoc)
-  u'<p>Hello!</p>\n'
\ No newline at end of file
+  u'<p>Hello!</p>\n'

Modified: Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/utilitymodule/browser.txt
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/utilitymodule/browser.txt	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/utilitymodule/browser.txt	2005-09-08 10:17:23 UTC (rev 38384)
@@ -123,7 +123,7 @@
 
   >>> iface = details.getInterface()
   >>> iface.getId()
-  '__builtin__.IBlah'
+  '__builtin__.IBlah ?'
 
 
 `getComponent()`
@@ -150,5 +150,5 @@
 Now we can get the component information:
 
   >>> pprint(details.getComponent())
-  {'path': '__builtin__.Foo',
-   'url': '__builtin__/Foo'}
+  {'path': '__builtin__.Foo ?',
+   'url': '__builtin__/Foo ?'}

Modified: Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/zcmlmodule/browser.txt
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/zcmlmodule/browser.txt	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/app/apidoc/zcmlmodule/browser.txt	2005-09-08 10:17:23 UTC (rev 38384)
@@ -186,8 +186,8 @@
 Return information about the directive handler object.
 
   >>> pprint(details.getHandler())
-  {'path': 'None.foo',
-   'url': 'None/foo'}
+  {'path': 'foo',
+   'url': 'foo'}
 
 
 `getSubdirectives()`
@@ -210,9 +210,9 @@
 the result becomes more interesting:
 
   >>> pprint(details.getSubdirectives()) #doctest:+ELLIPSIS
-  [{'handler': {'path': 'None.handler',
-                'url': 'None/handler'},
+  [{'handler': {'path': 'handler',
+                'url': 'handler'},
     'info': 'info',
     'name': 'foo',
     'namespace': 'browser',
-    'schema': <zope.app.apidoc.ifacemodule.browser.InterfaceDetails ...>}]
\ No newline at end of file
+    'schema': <zope.app.apidoc.ifacemodule.browser.InterfaceDetails ...>}]

Modified: Zope3/branches/jim-adapter-redesign/src/zope/app/authentication/browser/principalfolder.txt
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/app/authentication/browser/principalfolder.txt	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/app/authentication/browser/principalfolder.txt	2005-09-08 10:17:23 UTC (rev 38384)
@@ -246,7 +246,7 @@
   ... 
   ... users
   ... -----------------------------6519411471194050603270010787--
-  ... """)
+  ... """, handle_errors=False)
   HTTP/1.1 200 Ok
   ... 
 

Modified: Zope3/branches/jim-adapter-redesign/src/zope/app/component/adapter.py
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/app/component/adapter.py	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/app/component/adapter.py	2005-09-08 10:17:23 UTC (rev 38384)
@@ -25,36 +25,10 @@
 from zope.app.component import interfaces
 
 
-class LocalSurrogate(zope.interface.adapter.Surrogate):
-    """Local Surrogate
-
-    Local surrogates are transient, rather than persistent. Their adapter
-    data are stored in their registry objects.
-    """
-    def __init__(self, spec, registry):
-        super(LocalSurrogate, self).__init__(spec, registry)
-        self.registry = registry
-        registry.baseFor(spec).subscribe(self)
-
-    def clean(self):
-        spec = self.spec()
-        base = self.registry.baseFor(spec)
-        ladapters = self.registry.adapters.get(spec)
-        if ladapters:
-            adapters = base.adapters.copy()
-            adapters.update(ladapters)
-        else:
-            adapters = base.adapters
-        self.adapters = adapters
-        super(LocalSurrogate, self).clean()
-
-
 class LocalAdapterRegistry(zope.interface.adapter.AdapterRegistry,
                            persistent.Persistent):
     """Local/persistent surrogate registry"""
     zope.interface.implements(interfaces.ILocalAdapterRegistry)
-    
-    _surrogateClass = LocalSurrogate
 
     # See interfaces.registration.ILocatedRegistry
     next = None
@@ -82,24 +56,43 @@
         """See interfaces.registration.ILocatedRegistry"""
         if base is not None:
             self.base = base
-        if self.next is not None:
-            self.next.removeSub(self)
-        if next is not None:
-            next.addSub(self)
-        self.next = next
-        self.adaptersChanged()
 
+        if next != self.next:
+            if self.next is not None:
+                self.next.removeSub(self)
+            if next is not None:
+                next.addSub(self)
+            self.next = next
+
+        self.__bases__ = tuple([b for b in (next, self.base) if b is not None])
+
+        for sub in self.subs:
+            sub.setNext(self)
+            
+
     def register(self, registration):
         """See zope.app.component.interfaces.registration.IRegistry"""
         self._registrations += (registration,)
-        self.adaptersChanged()
 
+        zope.interface.adapter.AdapterRegistry.register(
+            self,
+            (registration.required, ) + registration.with,
+            registration.provided, registration.name,
+            registration.component,
+            )
+
     def unregister(self, registration):
         """See zope.app.component.interfaces.registration.IRegistry"""
         self._registrations = tuple([reg for reg in self._registrations
                                      if reg is not registration])
-        self.adaptersChanged()
 
+        zope.interface.adapter.AdapterRegistry.unregister(
+            self,
+            (registration.required, ) + registration.with,
+            registration.provided, registration.name,
+            registration.component,
+            )
+
     def registered(self, registration):
         """See zope.app.component.interfaces.registration.IRegistry"""
         return registration in self._registrations
@@ -108,76 +101,6 @@
         """See zope.app.component.interfaces.registration.IRegistry"""
         return self._registrations
 
-    def __getstate__(self):
-        state = persistent.Persistent.__getstate__(self).copy()
-        
-        for name in ('_default', '_null', 'adapter_hook',
-                     'lookup', 'lookup1', 'queryAdapter', 'get',
-                     'subscriptions', 'queryMultiAdapter', 'subscribers'
-                     ):
-            del state[name]
-        return state
-
-    def __setstate__(self, state):
-        persistent.Persistent.__setstate__(self, state)
-        zope.interface.adapter.AdapterRegistry.__init__(self)
-    
-    def baseFor(self, spec):
-        """Used by LocalSurrogate"""
-        return self.base.get(spec)
-
-    def _updateAdaptersFromRegistration(self, radapters, registration):
-        """Only to be used by _updateAdaptersFromLocalData, but can be
-        overridden to implement custom behavior."""
-        key = (False, registration.with, registration.name,
-               registration.provided)
-        radapters[key] = removeSecurityProxy(registration.component)
-
-    def _updateAdaptersFromLocalData(self, adapters):
-        """Update all adapter surrogates locally."""
-        for registration in self._registrations:
-            required = registration.required
-            if required is None:
-                required = zope.interface.adapter.Default
-            radapters = adapters.get(required)
-            if not radapters:
-                radapters = {}
-                adapters[required] = radapters
-
-            # Needs more thought:
-            # We have to remove the proxy because we're
-            # storing the value amd we can't store proxies.
-            # (Why can't we?)  we need to think more about
-            # why/if this is truly safe
-            self._updateAdaptersFromRegistration(radapters, registration)
-
-
-    def adaptersChanged(self):
-        """See interfaces.registration.ILocalAdapterRegistry"""
-        adapters = {}
-        if self.next is not None:
-            for required, radapters in self.next.adapters.iteritems():
-                adapters[required] = radapters.copy()
-        
-        self._updateAdaptersFromLocalData(adapters)
-
-        if adapters != self.adapters:
-            self.adapters = adapters
-
-            # Throw away all of our surrogates, rather than dirtrying
-            # them individually
-            super(LocalAdapterRegistry, self).__init__()
-            
-            for sub in self.subs:
-                sub.adaptersChanged()
-
-    def baseChanged(self):
-        """See interfaces.registration.ILocalAdapterRegistry"""
-        super(LocalAdapterRegistry, self).__init__()
-        for sub in self.subs:
-            sub.baseChanged()
-
-
 class AdapterRegistration(registration.ComponentRegistration):
     """A simple implementation of the adapter registration interface."""
     zope.interface.implements(interfaces.IAdapterRegistration)

Modified: Zope3/branches/jim-adapter-redesign/src/zope/app/component/interfaces/__init__.py
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/app/component/interfaces/__init__.py	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/app/component/interfaces/__init__.py	2005-09-08 10:17:23 UTC (rev 38384)
@@ -26,16 +26,8 @@
 
 class ILocalAdapterRegistry(registration.IRegistry,
                             registration.ILocatedRegistry):
+    pass
 
-    def adaptersChanged():
-        """Update the adapter surrogates, since the registrations changed."""
-
-    def baseChanged():
-        """Someone changed the base registry
-
-        This should only happen during testing
-        """
-
 class IPossibleSite(zope.interface.Interface):
     """An object that could be a site
     """

Modified: Zope3/branches/jim-adapter-redesign/src/zope/app/component/site.py
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/app/component/site.py	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/app/component/site.py	2005-09-08 10:17:23 UTC (rev 38384)
@@ -137,17 +137,48 @@
     """Custom local adapter registry for utilities, since utilities do not
     just register themselves as null adapters, but also as subscribers."""
 
-    def _updateAdaptersFromRegistration(self, radapters, registration):
-        # Register as null adapter
-        key = (False, registration.with, registration.name,
-               registration.provided)
-        radapters[key] = removeSecurityProxy(registration.component)
-        # Register as subscriber
-        key = (True, registration.with, '', registration.provided)
-        radapters[key] = radapters.get(key, ()) + (
-            removeSecurityProxy(registration.component), )
 
+    def register(self, registration):
+        """See zope.app.component.interfaces.registration.IRegistry"""
+        self._registrations += (registration,)
 
+        zope.interface.adapter.AdapterRegistry.register(
+            self,
+            (),
+            registration.provided, registration.name,
+            registration.component,
+            )
+
+        # XXX need test that this second part happens
+        zope.interface.adapter.AdapterRegistry.subscribe(
+            self,
+            (),
+            registration.provided,
+            registration.component,
+            )
+
+    def unregister(self, registration):
+        """See zope.app.component.interfaces.registration.IRegistry"""
+        self._registrations = tuple([reg for reg in self._registrations
+                                     if reg is not registration])
+
+        zope.interface.adapter.AdapterRegistry.unregister(
+            self,
+            (),
+            registration.provided, registration.name,
+            registration.component,
+            )
+
+
+        # XXX need test that this second part happens
+        zope.interface.adapter.AdapterRegistry.unsubscribe(
+            self,
+            (),
+            registration.provided,
+            registration.component,
+            )
+
+
 class LocalSiteManager(BTreeContainer,
                        bbb.site.BBBSiteManager,
                        zope.component.site.SiteManager):
@@ -284,12 +315,6 @@
     """
     zope.interface.implements(interfaces.IUtilityRegistration)
 
-    ############################################################
-    # Make the adapter code happy.
-    required = zope.interface.adapter.Null
-    with = ()
-    ############################################################
-
     def __init__(self, name, provided, component, permission=None):
         super(UtilityRegistration, self).__init__(component, permission)
         self.name = name

Modified: Zope3/branches/jim-adapter-redesign/src/zope/app/component/tests/test_adapter.py
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/app/component/tests/test_adapter.py	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/app/component/tests/test_adapter.py	2005-09-08 10:17:23 UTC (rev 38384)
@@ -115,13 +115,13 @@
 
    >>> G.lookup([IF0], IB1)
 
-   Note that it doesn't override the non-local adapter:
+   Note that it overrides the non-local adapter:
 
    >>> L1.lookup([IF2], IB1)
-   'A11G'
+   'A011'
    
    >>> L2.lookup([IF2], IB1)
-   'A11G'
+   'A011'
    
    because it was more specific.
 
@@ -137,18 +137,13 @@
    >>> L2.lookup([IF2], IB1)
    'A112'
    
-   But we still get the old one in L1
-
-   >>> L1.lookup([IF2], IB1)
-   'A11G'
-   
    Note that we can ask for less specific interfaces and still get the adapter:
 
    >>> L2.lookup([IF2], IB0)
    'A112'
 
    >>> L1.lookup([IF2], IB0)
-   'A11G'
+   'A011'
 
    We get the more specific adapter even if there is a less-specific
    adapter to B0:
@@ -177,12 +172,12 @@
    'A102'
 
    >>> L2.lookup([IF2], IB1)
-   'A10G'
+   'A011'
 
    >>> ra102.status = interfaces.registration.InactiveStatus
 
    >>> L2.lookup([IF2], IB0)
-   'A10G'
+   'A011'
 
    We can ask for all of the registrations :
 
@@ -247,15 +242,15 @@
 
     >>> G.lookup([IF0], IB1, 'bob')
 
-    Note that it doesn't override the non-local adapter:
+    Note that it overrides the non-local adapter:
 
     >>> L1.lookup([IF2], IB1)
     >>> L1.lookup([IF2], IB1, 'bob')
-    'A11G'
+    'A011'
 
     >>> L2.lookup([IF2], IB1)
     >>> L2.lookup([IF2], IB1, 'bob')
-    'A11G'
+    'A011'
 
     because it was more specific.
 
@@ -273,21 +268,16 @@
     >>> L2.lookup([IF2], IB1, 'bob')
     'A112'
 
-    But we still get thye old one in L1
+    Note that we can ask for less specific interfaces and still get
+    the adapter:
 
-    >>> L1.lookup([IF2], IB1)
-    >>> L1.lookup([IF2], IB1, 'bob')
-    'A11G'
-
-    Note that we can ask for less specific interfaces and still get the adapter:
-
     >>> L2.lookup([IF2], IB0)
     >>> L2.lookup([IF2], IB0, 'bob')
     'A112'
 
     >>> L1.lookup([IF2], IB0)
     >>> L1.lookup([IF2], IB0, 'bob')
-    'A11G'
+    'A011'
 
     We get the more specific adapter even if there is a less-specific
     adapter to B0:
@@ -321,13 +311,13 @@
 
     >>> L2.lookup([IF2], IB1)
     >>> L2.lookup([IF2], IB1, 'bob')
-    'A10G'
+    'A011'
 
     >>> ra102.status = interfaces.registration.InactiveStatus
 
     >>> L2.lookup([IF2], IB0)
     >>> L2.lookup([IF2], IB0, 'bob')
-    'A10G'
+    'A011'
     """
 
 def test_multi_adapters():
@@ -375,13 +365,13 @@
 
     >>> G.lookup((IF0, IR1), IB1, 'bob')
 
-    Note that it doesn't override the non-local adapter:
+    Note that overridea the non-local adapter:
 
     >>> L1.lookup([IF2, IR1], IB1, 'bob')
-    'A11G'
+    'A011'
 
     >>> L2.lookup((IF2, IR1), IB1, 'bob')
-    'A11G'
+    'A011'
 
     because it was more specific.
 
@@ -398,11 +388,6 @@
     >>> L2.lookup((IF2, IR1), IB1, 'bob')
     'A112'
 
-    But we still get the old one in L1
-
-    >>> L1.lookup((IF2, IR1), IB1, 'bob')
-    'A11G'
-
     Note that we can ask for less specific interfaces and still get
     the adapter:
 
@@ -410,7 +395,7 @@
     'A112'
 
     >>> L1.lookup((IF2, IR1), IB0, 'bob')
-    'A11G'
+    'A011'
 
     We get the more specific adapter even if there is a less-specific
     adapter to B0:
@@ -439,13 +424,13 @@
     'A102'
 
     >>> L2.lookup((IF2, IR1), IB1, 'bob')
-    'A10G'
+    'A011'
 
     >>> ra102.status = interfaces.registration.InactiveStatus
 
     >>> L2.lookup([IF2], IB0)
     >>> L2.lookup((IF2, IR1), IB0, 'bob')
-    'A10G'
+    'A011'
     """
 
 def test_persistence():
@@ -490,15 +475,15 @@
 
     >>> G.lookup([IF0], IB1)
 
-    Note that it doesn't override the non-local adapter:
+    Note that it overrides the non-local adapter:
 
     >>> L1.lookup([IF2], IB1)
     >>> L1.lookup([IF2], IB1, 'bob')
-    'A11G'
+    'A011'
 
     >>> L2.lookup([IF2], IB1)
     >>> L2.lookup([IF2], IB1, 'bob')
-    'A11G'
+    'A011'
 
     because it was more specific.
 
@@ -516,12 +501,6 @@
     >>> L2.lookup([IF2], IB1, 'bob')
     'A112'
 
-    But we still get the old one in L1
-
-    >>> L1.lookup([IF2], IB1)
-    >>> L1.lookup([IF2], IB1, 'bob')
-    'A11G'
-
     Note that we can ask for less specific interfaces and still get
     the adapter:
 
@@ -531,7 +510,7 @@
 
     >>> L1.lookup([IF2], IB0)
     >>> L1.lookup([IF2], IB0, 'bob')
-    'A11G'
+    'A011'
 
     We get the more specific adapter even if there is a less-specific
     adapter to B0:
@@ -555,9 +534,9 @@
     'A102'
 
     >>> L1.lookup([IF2], IB0, 'bob')
-    'A11G'
+    'A011'
     >>> L1.lookup([IF2], IB1, 'bob')
-    'A11G'
+    'A011'
     >>> L2.lookup([IF2], IB0, 'bob')
     'A102'
     >>> L2.lookup([IF2], IB1, 'bob')
@@ -577,9 +556,9 @@
     We should get the same outputs:
 
     >>> L1.lookup([IF2], IB0, 'bob')
-    'A11G'
+    'A011'
     >>> L1.lookup([IF2], IB1, 'bob')
-    'A11G'
+    'A011'
     >>> L2.lookup([IF2], IB0, 'bob')
     'A102'
     >>> L2.lookup([IF2], IB1, 'bob')
@@ -592,13 +571,13 @@
     >>> ra102.status = interfaces.registration.InactiveStatus
 
     >>> L1.lookup([IF2], IB0, 'bob')
-    'A11G'
+    'A011'
     >>> L1.lookup([IF2], IB1, 'bob')
-    'A11G'
+    'A011'
     >>> L2.lookup([IF2], IB0, 'bob')
-    'A11G'
+    'A011'
     >>> L2.lookup([IF2], IB1, 'bob')
-    'A11G'
+    'A011'
 
     >>> transaction.commit()
 
@@ -611,13 +590,13 @@
     We should see the result of the deactivations:
     
     >>> L1.lookup([IF2], IB0, 'bob')
-    'A11G'
+    'A011'
     >>> L1.lookup([IF2], IB1, 'bob')
-    'A11G'
+    'A011'
     >>> L2.lookup([IF2], IB0, 'bob')
-    'A11G'
+    'A011'
     >>> L2.lookup([IF2], IB1, 'bob')
-    'A11G'
+    'A011'
 
     Cleanup:
     >>> G.__init__()

Modified: Zope3/branches/jim-adapter-redesign/src/zope/app/component/tests/test_directives.py
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/app/component/tests/test_directives.py	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/app/component/tests/test_directives.py	2005-09-08 10:17:23 UTC (rev 38384)
@@ -42,7 +42,8 @@
 from zope.app.testing.placelesssetup import PlacelessSetup
 from zope.app.component.interface import queryInterface
 from zope.app.component.metaconfigure import interface
-from zope.app.component.tests.adapter import A1, A2, A3, I1, I3, IS, Handler
+from zope.app.component.tests.adapter import A1, A2, A3, Handler
+from zope.app.component.tests.adapter import I1, I2, I3, IS
 from zope.app.component.tests.components import IContent, Content, Comp, comp
 from zope.app.component.tests.components import IApp
 from zope.app.component.tests.views import IV, IC, V1, R1, IR
@@ -161,15 +162,9 @@
             '''
             )))
 
-        content = Content()
-        a1 = A1()
-        a2 = A2()
-        subscribers = zapi.subscribers((content, a1, a2), None)
-
-        a3 = subscribers[0]
-
-        self.assertEqual(a3.__class__, A3)
-        self.assertEqual(a3.context, (content, a1, a2))
+        sm = zapi.getSiteManager()
+        a3 = sm.adapters.subscriptions((IContent, I1, I2), None)[0]
+        self.assertEqual(a3, A3)
         
 
     def testTrustedSubscriber(self):

Modified: Zope3/branches/jim-adapter-redesign/src/zope/app/debugskin/configure.zcml
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/app/debugskin/configure.zcml	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/app/debugskin/configure.zcml	2005-09-08 10:17:23 UTC (rev 38384)
@@ -21,4 +21,16 @@
       permission="zope.Public"
       layer="debug" />
 
+  <!-- Need to repeat for NotFound to override default view -->
+  <!-- XXX there is a functional test for NotFound. Did it really
+       mean to test the IException registration?
+        --> 
+  <page 
+      name="index.html"
+      template="error_debug.pt"
+      for="zope.publisher.interfaces.INotFound"
+      class=".exceptions.ExceptionDebugView"
+      permission="zope.Public"
+      layer="debug" />
+
 </configure>

Modified: Zope3/branches/jim-adapter-redesign/src/zope/app/form/browser/configure.zcml
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/app/form/browser/configure.zcml	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/app/form/browser/configure.zcml	2005-09-08 10:17:23 UTC (rev 38384)
@@ -259,7 +259,6 @@
       factory=".CollectionDisplayWidget"
       permission="zope.Public"
       />
-
   <view
       type="zope.publisher.interfaces.browser.IBrowserRequest"
       for="zope.schema.interfaces.ICollection"
@@ -268,6 +267,29 @@
       permission="zope.Public"
       />
 
+  <!-- XXX
+
+       Need to repeat the above for Sequence to avoid being overridden by a
+       DAV widget.  This suggests that we should be getting something
+       more specific than IInputWidget.
+
+       -->
+  <view
+      type="zope.publisher.interfaces.browser.IBrowserRequest"
+      for="zope.schema.interfaces.ISequence"
+      provides="zope.app.form.interfaces.IDisplayWidget"
+      factory=".CollectionDisplayWidget"
+      permission="zope.Public"
+      />
+  <view
+      type="zope.publisher.interfaces.browser.IBrowserRequest"
+      for="zope.schema.interfaces.ISequence"
+      provides="zope.app.form.interfaces.IInputWidget"
+      factory=".CollectionInputWidget"
+      permission="zope.Public"
+      />
+
+
   <!-- non-choice collection fields should register for the field + value type
        so as to allow specific field + value_type widgets such as the Choice
        pattern -->

Modified: Zope3/branches/jim-adapter-redesign/src/zope/app/locking/tests.py
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/app/locking/tests.py	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/app/locking/tests.py	2005-09-08 10:17:23 UTC (rev 38384)
@@ -54,6 +54,9 @@
     def __cmp__(self, other):
         return cmp(id(self.object), id(other.object))
 
+def maybeFakeKeyReference(ob):
+    if not isinstance(ob, int):
+        return FakeKeyReference(ob)
 
 
 def setUp(test):
@@ -71,7 +74,7 @@
     from zope.app.locking.storage import ILockStorage, PersistentLockStorage
     from zope.app.traversing.interfaces import IPathAdapter
 
-    ztapi.provideAdapter(Interface, IKeyReference, FakeKeyReference)
+    ztapi.provideAdapter(Interface, IKeyReference, maybeFakeKeyReference)
     ztapi.provideAdapter(Interface, ILockable, LockingAdapterFactory)
     ztapi.provideAdapter(None, IPathAdapter, LockingPathAdapter,
                          "locking")

Modified: Zope3/branches/jim-adapter-redesign/src/zope/app/module/README.txt
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/app/module/README.txt	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/app/module/README.txt	2005-09-08 10:17:23 UTC (rev 38384)
@@ -113,7 +113,7 @@
   >>> ZopeModuleRegistry.findModule('mymodule') is module
   True
   >>> ZopeModuleRegistry.modules()
-  ['mymodule']
+  [u'mymodule']
 
 Additionally, the package provides two API functions that look up a module in
 the registry and then in `sys.modules`:
@@ -149,4 +149,4 @@
 
   >>> zope.app.module.uninstallPersistentModuleImporter(event)
   >>> __builtin__.__import__
-  <built-in function __import__>
\ No newline at end of file
+  <built-in function __import__>

Modified: Zope3/branches/jim-adapter-redesign/src/zope/app/pagetemplate/configure.zcml
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/app/pagetemplate/configure.zcml	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/app/pagetemplate/configure.zcml	2005-09-08 10:17:23 UTC (rev 38384)
@@ -44,4 +44,11 @@
     <allow attributes="__call__" />
  </class>
 
+ <adapter
+     for="zope.app.pagetemplate.viewpagetemplatefile.BoundPageTemplate
+          zope.publisher.interfaces.browser.IBrowserRequest"
+     provides="zope.publisher.interfaces.browser.IBrowserPublisher"
+     factory="zope.app.publication.traversers.NoTraverser"
+     />
+
 </configure>

Modified: Zope3/branches/jim-adapter-redesign/src/zope/app/publication/traversers.py
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/app/publication/traversers.py	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/app/publication/traversers.py	2005-09-08 10:17:23 UTC (rev 38384)
@@ -67,6 +67,9 @@
 
         return view, path
 
+def NoTraverser(ob, request):
+    return None
+
 class TestTraverser(object):
     """Bobo-style traverser, mostly useful for testing"""
     implements(IBrowserPublisher)
@@ -77,7 +80,7 @@
     def browserDefault(self, request):
         ob = self.context
 
-        if providedBy(ob):
+        if list(providedBy(ob)):
             view_name = zapi.getDefaultViewName(ob, request)
             return ob, (("@@%s" % view_name),)
 

Modified: Zope3/branches/jim-adapter-redesign/src/zope/app/traversing/browser/configure.zcml
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/app/traversing/browser/configure.zcml	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/app/traversing/browser/configure.zcml	2005-09-08 10:17:23 UTC (rev 38384)
@@ -10,6 +10,12 @@
       permission="zope.Public"
       />
 
+  <adapter
+      for="types.MethodType zope.publisher.interfaces.browser.IBrowserRequest"
+      provides="zope.publisher.interfaces.browser.IBrowserPublisher"
+      factory="zope.app.publication.traversers.NoTraverser"
+      />
+
   <view
       for="zope.app.container.interfaces.IItemContainer"
       type="zope.publisher.interfaces.browser.IBrowserRequest"

Modified: Zope3/branches/jim-adapter-redesign/src/zope/component/site.py
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/component/site.py	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/component/site.py	2005-09-08 10:17:23 UTC (rev 38384)
@@ -18,9 +18,10 @@
 __docformat__ = "reStructuredText"
 import types
 
+from zope import interface
 from zope.interface import implements, providedBy, implementedBy, declarations
 from zope.interface.adapter import AdapterRegistry
-from zope.interface.interfaces import IInterface
+from zope.interface.interfaces import ISpecification
 
 from zope.component.interfaces import ISiteManager, IRegistry
 from zope.component.interfaces import ComponentLookupError, Invalid
@@ -90,21 +91,13 @@
     
     def queryUtility(self, interface, name='', default=None):
         """See ISiteManager interface"""
+        return self.utilities.lookup((), interface, name, default)
 
-        byname = self.utilities._null.get(interface)
-        if byname:
-            return byname.get(name, default)
-        else:
-            return default
-
     def getUtilitiesFor(self, interface):
-        byname = self.utilities._null.get(interface)
-        if byname:
-            for item in byname.iteritems():
-                yield item
+        return self.utilities.lookupAll((), interface)
 
     def getAllUtilitiesRegisteredFor(self, interface):
-        return iter(self.utilities._null.get(('s', interface)) or ())
+        return self.utilities.subscriptions((), interface)
 
 
 class GlobalSiteManager(SiteManager):
@@ -114,7 +107,7 @@
 
     def __init__(self, name=None):
         self.__name__ = name
-        self._registrations = {}
+        self._registrations = []
         self.adapters = GlobalAdapterRegistry(self, 'adapters')
         self.utilities = GlobalAdapterRegistry(self, 'utilities')
 
@@ -164,19 +157,12 @@
         >>> registry.queryMultiAdapter((O1(), O2()), R1, '').__class__
         <class 'zope.component.site.O3'>
         """
-        ifaces = []
-        for iface in required:
-            if not IInterface.providedBy(iface) and iface is not None:
-                if not isinstance(iface, (type, types.ClassType)):
-                    raise TypeError(iface, IInterface)
-                iface = implementedBy(iface)
+        required = tuple(map(_spec, required))
 
-            ifaces.append(iface)
-        required = tuple(ifaces)
+        self._registrations.append(
+            AdapterRegistration(required, provided, name, factory, info),
+            )
 
-        self._registrations[(required, provided, name)] = AdapterRegistration(
-            required, provided, name, factory, info)
-
         self.adapters.register(required, provided, name, factory)
 
     def subscribe(self, required, provided, factory, info=''):
@@ -208,25 +194,11 @@
         SubscriptionRegistration(('R1',), 'P2', 'c1', 'd1')
         SubscriptionRegistration(('R1',), 'P2', 'c2', 'd2')
         """
-        ifaces = []
-        for iface in required:
-            if not IInterface.providedBy(iface) and \
-                   not isinstance(iface, declarations.Implements) and \
-                   iface is not None:
-                if not isinstance(iface, (type, types.ClassType)):
-                    raise TypeError(iface, IInterface)
-                iface = implementedBy(iface)
 
-            ifaces.append(iface)
-        required = tuple(ifaces)
+        required = tuple(map(_spec, required))
 
-        registration = SubscriptionRegistration(
-            required, provided, factory, info)
-
-        self._registrations[(required, provided)] = (
-            self._registrations.get((required, provided), ())
-            +
-            (registration, )
+        self._registrations.append(
+            SubscriptionRegistration(required, provided, factory, info),
             )
 
         self.adapters.subscribe(required, provided, factory)
@@ -243,22 +215,28 @@
         # Also subscribe to support getAllUtilitiesRegisteredFor:
         self.utilities.subscribe((), providedInterface, component)
 
-        self._registrations[(providedInterface, name)] = UtilityRegistration(
-            providedInterface, name, component, info)
+        self._registrations.append(
+            UtilityRegistration(providedInterface, name, component, info),
+            )
 
     def registrations(self):
-        for registration in self._registrations.itervalues():
-            if isinstance(registration, tuple):
-                for r in registration:
-                    yield r
-            else:
-                yield registration
+        return iter(self._registrations)
 
     def __reduce__(self):
         # Global site managers are pickled as global objects
         return self.__name__
 
+_class_types = (type, types.ClassType)
+def _spec(iface_or_class):
+    if ISpecification.providedBy(iface_or_class):
+        return iface_or_class
+    if iface_or_class is None:
+        return interface.Interface
+    if isinstance(iface_or_class, _class_types):
+        return interface.implementedBy(iface_or_class)
+    raise TypeError(iface_or_class, ISpecification)
 
+
 def GAR(siteManager, registryName):
     return getattr(siteManager, registryName)
 

Modified: Zope3/branches/jim-adapter-redesign/src/zope/interface/_zope_interface_coptimizations.c
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/interface/_zope_interface_coptimizations.c	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/interface/_zope_interface_coptimizations.c	2005-09-08 10:17:23 UTC (rev 38384)
@@ -23,6 +23,7 @@
 static PyObject *BuiltinImplementationSpecifications, *str__provides__;
 static PyObject *str__class__, *str__providedBy__, *strisOrExtends;
 static PyObject *empty, *fallback, *str_implied, *str_cls, *str_implements;
+static PyObject *str__sro__;
 static PyTypeObject *Implements;
 
 static int imported_declarations = 0;
@@ -487,7 +488,425 @@
         /* tp_descr_get      */ (descrgetfunc)CPB_descr_get,
 };
 
+/* 
 
+def _lookup(components, specs, i, l):
+    if i < l:
+        for spec in specs[i].__sro__:
+            comps = components.get(spec)
+            if comps is not None:
+                r = _lookup(comps, specs, i+1, l)
+                if r is not None:
+                    return r
+        return None
+    
+    return components
+ */
+static PyObject *
+_lookup(PyObject *components, PyObject *specs, int i, int l)
+{
+  /* Note that result is NOT increfed */
+
+  PyObject *specs_i, *spec, *sro, *comps;
+  int ls, is;
+
+  if (i < l)
+    {
+      specs_i = PyTuple_GET_ITEM(specs, i);
+      if (specs_i != NULL)
+        { 
+          sro = PyObject_GetAttr(specs_i, str__sro__);
+          if (sro == NULL)
+            return NULL;
+          ls = PyTuple_Size(sro);
+          if (ls < 0)
+            {
+              Py_DECREF(sro);
+              return NULL;
+            }
+          for (is = 0; is < ls; is++)
+            {
+              spec = PyTuple_GET_ITEM(sro, is);
+              if (spec == NULL)
+                continue;
+              comps = PyDict_GetItem(components, spec);
+              if (comps == NULL)
+                continue;
+              comps = _lookup(comps, specs, i+1, l);
+              if (comps != Py_None)
+                {
+                  Py_DECREF(sro);
+                  return comps;
+                }
+            }
+          
+        }
+      return Py_None;
+    }
+
+  return components;
+}
+
+static PyObject *
+tuple(PyObject *iterable)
+{
+  if (PyTuple_Check(iterable))
+    {
+      Py_INCREF(iterable);
+      return iterable;
+    }
+  return PyObject_CallFunctionObjArgs((PyObject*)&PyTuple_Type, iterable, 
+                                      NULL);
+}
+
+/* 
+
+def lookup(components, required, provided):
+    components = components.get(provided)
+    if components:
+
+        if required:
+            components = find(components, required, 0, len(required))
+            if not components:
+                return None
+
+        return components[0][0]
+
+    return None
+
+ */
+static PyObject *
+lookup(PyObject *ignored, PyObject *args)
+{
+  PyObject *components, *required, *provided, *result=Py_None;
+  int l;
+  
+  if (PyArg_ParseTuple(args, "O!OO", 
+                       &PyDict_Type, &components, &required, &provided) 
+      == 0)
+    return NULL;
+
+  required = tuple(required);
+  if (required == NULL)
+    goto err;
+
+  components = PyDict_GetItem(components, provided);
+  if (components != NULL)
+    {
+      l = PyTuple_GET_SIZE(required);
+      if (l > 0)
+        {
+          components = _lookup(components, required, 0, l);
+          if (components == Py_None)
+            goto done;
+        }
+
+      components = PyTuple_GetItem(components, 0);
+      if (components == NULL)
+        return NULL;
+      result = PyTuple_GetItem(components, 0);
+    }
+
+ done:
+  Py_DECREF(required);
+  Py_INCREF(result);
+  return result;
+
+ err:
+  Py_DECREF(required);
+  return NULL;
+}
+
+/* 
+
+def lookup1(components, required, provided):
+    components = components.get(provided)
+    if components:
+        for s in required.__sro__:
+            comps = components.get(s)
+            if comps:
+                return comps[0][0]
+
+    return None
+
+ */
+
+static PyObject *
+lookup1(PyObject *ignored, PyObject *args)
+{
+  PyObject *components, *required, *provided, *r=Py_None;
+  
+  if (PyArg_ParseTuple(args, "O!OO", 
+                       &PyDict_Type, &components, &required, &provided) 
+      == 0)
+    return NULL;
+
+  components = PyDict_GetItem(components, provided);
+  if (components != NULL)
+    {
+      PyObject *sro;
+      int is, ls;
+
+      sro = PyObject_GetAttr(required, str__sro__);
+      if (sro == NULL)
+        return NULL;
+      ls = PyTuple_Size(sro);
+      if (ls < 0)
+        {
+          Py_DECREF(sro);
+          return NULL;
+        }
+  
+      for (is = 0; is < ls; is++)
+        {
+          PyObject *spec, *comps;
+          int l;
+
+          spec = PyTuple_GET_ITEM(sro, is);
+          if (spec == NULL)
+            continue;
+          comps = PyDict_GetItem(components, spec);
+          if (comps == NULL)
+            continue;
+          l = PyTuple_Size(comps);
+          if (l == 0)
+            continue;
+          if (l < 0)
+            r = NULL;
+          else
+            {
+              r = PyTuple_GET_ITEM(comps, 0);
+              r = PyTuple_GetItem(r, 0);
+            }
+          break;
+        }
+      
+      Py_DECREF(sro);
+    }
+
+  Py_XINCREF(r);
+  return r;
+}
+
+/* 
+
+def _subscribers(components, specs, i, l, objects, result):
+    if i < l:
+        sro = list(specs[i].__sro__)
+        sro.reverse()
+        for spec in sro:
+            comps = components.get(spec)
+            if comps is not None:
+                _subscribers(comps, specs, i+1, l, objects, result)
+    else:
+        if objects is None:
+            result.extend([c[0] for c in components])
+        else:
+            for c in components:
+                c = c[0](*objects)
+                if c is not None and result is not None:
+                    result.append(c)
+
+ */
+
+static int
+_subscribers(PyObject *components, PyObject *specs, int i, int l, 
+             PyObject *objects, PyObject *result)
+{
+  PyObject *comps;
+
+  if (i < l)
+    {
+      PyObject *sro, *spec;
+      int ls;
+
+      spec = PyTuple_GET_ITEM(specs, i);
+      if (specs == NULL)
+        return 0; /* should never happen. Treat as empty spec. */
+
+      sro = PyObject_GetAttr(spec, str__sro__);
+      if (sro == NULL)
+        return -1;
+      ls = PyTuple_Size(sro);
+      if (ls < 0)
+        {
+          Py_DECREF(sro);
+          return -1;
+        }
+      for (ls-- ; ls >= 0; ls--)
+        {
+          spec = PyTuple_GET_ITEM(sro, ls);
+          if (spec == NULL)
+            continue;
+          comps = PyDict_GetItem(components, spec);
+          if (comps == NULL)
+            continue;
+          if (_subscribers(comps, specs, i+1, l, objects, result) < 0)
+            {
+              Py_DECREF(sro);
+              return -1;
+            }
+        }
+      Py_DECREF(sro);
+    }
+  else
+    {
+      l = PyTuple_Size(components);
+      if (l < 0)
+        return -1;
+      for (i=0; i < l; i++)
+        {
+          comps = PyTuple_GET_ITEM(components, i);
+          comps = PyTuple_GetItem(comps, 0);
+          if (comps == NULL)
+            return -1;
+
+          if (objects != NULL)
+            {
+              comps = PyObject_CallObject(comps, objects);
+              if (comps == NULL)
+                return -1;
+
+              if (result != NULL && comps != Py_None)
+                {
+                  int a = 0;
+
+                  a = PyList_Append(result, comps);
+                  Py_DECREF(comps);
+                  if (a < 0)
+                    return -1;
+                }
+              else
+                Py_DECREF(comps);
+            }
+          else if (PyList_Append(result, comps) < 0)
+            /* if objects is NULL, then result is not NULL */
+            return -1;
+        }
+    }
+  
+  return 0;
+}
+
+/* 
+
+def subscriptions(components, required, provided, result):
+    components = components.get(provided)
+    if components:
+        _subsciptions(components, required, 0, len(required), result)
+ */
+static PyObject *
+subscriptions(PyObject *ignored, PyObject *args)
+{
+  PyObject *components, *required, *provided, *result;
+  
+  if (PyArg_ParseTuple(args, "O!OOO", 
+                       &PyDict_Type, &components, &required, &provided,
+                       &result) 
+      == 0)
+    return NULL;
+
+  required = tuple(required);
+  if (required == NULL)
+    return NULL;
+
+  components = PyDict_GetItem(components, provided);
+  if (components != NULL)
+    {
+      int l;
+
+      l = PyTuple_GET_SIZE(required);
+      if (_subscribers(components, required, 0, l, NULL, result) < 0)
+        goto err;
+    }
+
+  Py_DECREF(required);
+  Py_INCREF(Py_None);
+  return Py_None;
+
+ err:
+  Py_DECREF(required);
+  return NULL;
+}
+
+/* 
+
+def subscribers(components, objects, provided, result):
+    components = components.get(provided)
+    if not components:
+        return
+
+    required = map(providedBy, objects)
+
+    if provided is None:
+        result == None
+
+    _subscribers(components, required, 0, len(required), objects, result)
+
+ */
+static PyObject *
+subscribers(PyObject *ignored, PyObject *args)
+{
+  PyObject *components, *objects, *provided, *result;
+  
+  if (PyArg_ParseTuple(args, "O!OOO", 
+                       &PyDict_Type, &components, 
+                       &objects, &provided,
+                       &result) 
+      == 0)
+    return NULL;
+
+  objects = tuple(objects);
+  if (objects == NULL)
+    return NULL;
+
+  components = PyDict_GetItem(components, provided);
+  if (components != NULL)
+    {
+      int i, l;
+      PyObject *required;
+
+      l = PyTuple_GET_SIZE(objects);
+      required = PyTuple_New(l);
+      if (required == NULL)
+        goto err;
+
+      for (i=0; i < l; i++)
+        {
+          PyObject *o;
+
+          o = PyTuple_GET_ITEM(objects, i);
+          if (o == NULL)
+            continue;
+          o = providedBy(NULL, o);
+          if (o == NULL)
+            {
+              Py_DECREF(required);
+              goto err;
+            }
+          PyTuple_SET_ITEM(required, i, o);
+        }
+
+      if (provided == Py_None)
+        result = NULL;
+      
+      i = _subscribers(components, required, 0, l, objects, result);
+      Py_DECREF(required);
+
+      if (i < 0)
+        goto err;
+    }
+
+  Py_DECREF(objects);
+  Py_INCREF(Py_None);
+  return Py_None;
+
+ err:
+  Py_DECREF(objects);
+  return NULL;
+}
+
+
 static struct PyMethodDef m_methods[] = {
   {"implementedBy", (PyCFunction)implementedBy, METH_O,
    "Interfaces implemented by instances of a class"},
@@ -495,6 +914,24 @@
    "Get an object's interfaces (internal api)"},
   {"providedBy", (PyCFunction)providedBy, METH_O,
    "Get an object's interfaces"},
+
+  {"lookup", (PyCFunction)lookup, METH_VARARGS,
+   "lookup(components, required, provided) -- lookup a multi-adapter factory"
+  },
+
+  {"lookup1", (PyCFunction)lookup1, METH_VARARGS,
+   "lookup(components, required, provided) -- lookup an adapter factory"
+  },
+
+  {"subscriptions", (PyCFunction)subscriptions, METH_VARARGS,
+   "subscriptions(components, required, provided, result)"
+   " -- find subscriptions"
+  },
+
+  {"subscribers", (PyCFunction)subscribers, METH_VARARGS,
+   "subscriptions(components, objects, provided, result)"
+   " -- find subscriptions"
+  },
   
   {NULL,	 (PyCFunction)NULL, 0, NULL}		/* sentinel */
 };
@@ -520,6 +957,7 @@
   DEFINE_STRING(_implied);
   DEFINE_STRING(_implements);
   DEFINE_STRING(_cls);
+  DEFINE_STRING(__sro__);
 #undef DEFINE_STRING
   
         

Modified: Zope3/branches/jim-adapter-redesign/src/zope/interface/adapter.py
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/interface/adapter.py	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/interface/adapter.py	2005-09-08 10:17:23 UTC (rev 38384)
@@ -1,746 +1,436 @@
-############################################################################
+##############################################################################
 #
-# Copyright (c) 2002 Zope Corporation and Contributors.
+# Copyright (c) 2004 Zope Corporation and Contributors.
 # All Rights Reserved.
 #
 # This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
 # FOR A PARTICULAR PURPOSE.
 #
-############################################################################
-"""Adapter-style interface registry
+##############################################################################
+"""Adapter management
 
-This implementation is based on a notion of "surrogate" interfaces.
-
 $Id$
 """
 
-# Implementation notes
+from zope.interface import providedBy, Interface, ro
 
-# We keep a collection of surrogates.
+_marker = object
+class AdapterRegistry(object):
 
-# A surrogate is a surrogate for a specification (interface or
-# declaration).  We use weak references in order to remove surrogates
-# if the corresponding specification goes away.
+    def __init__(self, bases=()):
+        self._unnamed_adapters = [] # [{ provided -> components }]
+        self._named_adapters = {} # { name -> [{ provided -> components }] }
+        self._unnamed_subscriptions = [] # ditto
+        self._named_subscriptions = {} # ditto
+        self.__bases__ = bases
 
-# Each surrogate keeps track of:
+    def __bases__():
+        def get(self):
+            return self.__dict__['__bases__']
+        def set(self, v):
+            self.__dict__['__bases__'] = v
+            self.ro = ro.ro(self)
+            
+        return property(get, set)
+    __bases__ = __bases__()
+        
+    def register(self, required, provided, name, value):
+        if value is None:
+            self.unregister(required, provided, name, value)
+            return
 
-# - The adapters registered directly for that surrogate, and
+        if name:
+            name = _normalize_name(name)
+            byorder = self._named_adapters.get(name)
+            if byorder is None:
+                self._named_adapters[name] = byorder = []
+        else:
+            byorder = self._unnamed_adapters
 
-# - The "implied" adapters, which is the adapters that can be computed
-#   from instances of that surrogate.
+        order = len(required)
+        while len(byorder) <= order:
+            byorder.append(Adapters())
 
-# The later data structure takes into account adapters registered for
-# specifications that the registered surrogate extends.
+        components = byorder[order]
+        components.register(required, provided, value)
+        
+    def unregister(self, required, provided, name, value=None):
+        if name:
+            name = _normalize_name(name)
+            byorder = self._named_adapters.get(name)
+            if byorder is None:
+                return
+        else:
+            byorder = self._unnamed_adapters
 
-# The registrations are of the form:
+        order = len(required)
+        if order >= len(byorder):
+            return
+        components = byorder[order]
+        components.unregister(required, provided, value)
 
-#   {(subscription, with, name, specification) -> factories}
 
-# where:
+    def lookup(self, required, provided, name=u'', default=None):
+        for self in self.ro:
+            if name:
+                byorder = self._named_adapters.get(name)
+                if byorder is None:
+                    continue
+            else:
+                byorder = self._unnamed_adapters
 
-#   'subscription' is a flag indicating if this registration is for
-#   subscription adapters.
+            order = len(required)
+            if order >= len(byorder):
+                continue
 
-#   'with' is a tuple of specs that is non-empty only in the case
-#   of multi-adapters.  
+            components = byorder[order]
+            result = lookup(components.components, required, provided)
+            if result is not None:
+                return result
 
-#   'name' is a unicode adapter name.  Unnamed adapters have an empty
-#   name.
+        return default
 
-#   'specification' is the interface being adapted to.
+    def queryMultiAdapter(self, objects, provided, name=u'', default=None):
+        factory = self.lookup(map(providedBy, objects), provided, name)
+        if factory is None:
+            return default
 
-#   'factories' is normally a tuple of factories, but can be anything.
-#   (See the "raw" option to the query-adapter calls.)  For subscription
-#   adapters, it is a tuple of tuples of factories.
+        result = factory(*objects)
+        if result is None:
+            return default
 
-# The implied adapters are held in a single dictionary. The items in the
-# dictionary are of several forms:
+        return result        
 
-# For single adapters:
-#
-# {specification -> {name -> object}
-#
-# where object is usually a sequence of factories
+    def lookup1(self, required, provided, name=u'', default=None):
+        for self in self.ro:
+            if name:
+                byorder = self._named_adapters.get(name)
+                if byorder is None:
+                    continue
+            else:
+                byorder = self._unnamed_adapters
 
-# For multiple adapters:
-#
-# {(specification, order) -> {name -> {with -> object}}}
+            if 1 >= len(byorder):
+                continue
 
-# For single subscription adapters:
-#
-# {('s', specification) -> tuple([object])}
+            components = byorder[1]
+            result = lookup1(components.components, required, provided)
+            if result is not None:
+                return result
 
-# For multiple-subscription adapters:
-#
-# {('s', specification, order) -> {with -> tuple([object])}}
+        return default
 
+    def queryAdapter(self, object, provided, name=u'', default=None):
+        return self.adapter_hook(provided, object, name, default)
 
-from __future__ import generators
+    def adapter_hook(self, provided, object, name=u'', default=None):
+        factory = self.lookup1(providedBy(object), provided, name)
+        if factory is not None:
+            result = factory(object)
+            if result is not None:
+                return result
 
-import weakref
-from zope.interface.ro import ro
-from zope.interface.declarations import providedBy
-from zope.interface.interface import InterfaceClass, Interface
+        return default
 
-Default = InterfaceClass("Default", (), {})
-Null = InterfaceClass("Null", (), {})
+    def lookupAll(self, required, provided):
+        for self in self.ro:
+            order = len(required)
+            if order < len(self._unnamed_adapters):
+                result = lookup(self._unnamed_adapters[order].components,
+                                required, provided)
+                if result is not None:
+                    yield (u'', result)
 
-# 2.2 backwards compatability
-try:
-    enumerate
-except NameError:
-    def enumerate(l):
-        i = 0
-        for o in l:
-            yield i, o
-            i += 1
-try:
-    basestring
-except NameError:
-    basestring = (str, unicode)
+            for name, byorder in self._named_adapters.iteritems():
+                if order < len(byorder):
+                    result = lookup(byorder[order].components,
+                                    required, provided)
+                    if result is not None:
+                        yield (name, result)
 
+    def names(self, required, provided):
+        return [c[0] for c in self.lookupAll(required, provided)]
 
-class ReadProperty(object):
+    def subscribe(self, required, provided, value):
 
-    def __init__(self, func):
-        self.func = func
+# XXX when we are ready to support named subscribers, we'll add a name
+# argument and uncomment the following.
+##         if name:
+##             name = _normalize_name(name)
+##             byorder = self._named_subscriptions.get(name)
+##             if byorder is None:
+##                 self._named_subscriptions[name] = byorder = []
+##         else:
+##             byorder = self._unnamed_subscriptions
 
-    def __get__(self, inst, class_):
-        if inst is None:
-            return self
-        return self.func(inst)
+        byorder = self._unnamed_subscriptions
 
-class Surrogate(object):
-    """Specification surrogate
+        order = len(required)
+        while len(byorder) <= order:
+            byorder.append(Subscriptions())
 
-    A specification surrogate is used to hold adapter registrations on
-    behalf of a specification.
-    """
+        components = byorder[order]
+        components.register(required, provided, value)
 
-    def __init__(self, spec, registry):
-        self.spec = spec.weakref()
-        self.registry = registry
-        spec.subscribe(self)
-        self.adapters = {}
-        self.dependents = weakref.WeakKeyDictionary()
+    def unsubscribe(self, required, provided, value):
 
-        self.registry = registry
-        self.__bases__ = [registry.get(base) for base in spec.__bases__]
-        for base in self.__bases__:
-            base.subscribe(self)
+# XXX when we are ready to support named subscribers, we'll add a name
+# argument and uncomment the following.
+##         if name:
+##             name = _normalize_name(name)
+##             byorder = self._named_subscriptions.get(name)
+##             if byorder is None:
+##                 self._named_subscriptions[name] = byorder = []
+##         else:
+##             byorder = self._unnamed_subscriptions
 
-    def dirty(self):
-        if 'get' in self.__dict__:
-            # Not already dirty
-            del self.selfImplied
-            del self.multImplied
-            del self.get
+        byorder = self._unnamed_subscriptions
 
-        bases = [self.registry.get(base) for base in self.spec().__bases__]
-        if bases != self.__bases__:
-            # Our bases changed. unsubscribe from the old ones
-            # and subscribe to the new ones
-            for base in self.__bases__:
-                base.unsubscribe(self)
+        order = len(required)
+        if len(byorder) <= order:
+            return
 
-            self.__bases__ = bases
-            for base in bases:
-                base.subscribe(self)
+        components = byorder[order]
+        components.unregister(required, provided, value)
 
-        for dependent in self.dependents.keys():
-            dependent.dirty()
+    def subscriptions(self, required, provided, name=u''):
+        result = []
+        # XXX should we traverse ro in reverse?
+        for self in self.ro:
+            if name:
+                byorder = self._named_subscriptions.get(name)
+                if byorder is None:
+                    continue
+            else:
+                byorder = self._unnamed_subscriptions
 
-    def clean(self):
-        for base in self.__bases__:
-            base.unsubscribe(self)
-        self.__bases__ = [self.registry.get(base)
-                          for base in self.spec().__bases__]
-        for base in self.__bases__:
-            base.subscribe(self)
-
-        self.selfImplied, self.multImplied = adapterImplied(self.adapters)
-
-        implied = {}
-
-        ancestors = ro(self)
-
-        # Collect implied data in reverse order to have more specific data
-        # override less-specific data.
-        ancestors.reverse()
-        for ancestor in ancestors:
+            order = len(required)
+            if order >= len(byorder):
+                continue
             
-            for key, v in ancestor.selfImplied.iteritems():
+            subscriptions(byorder[order].components, required, provided,
+                          result)
 
-                # key is specification or ('s', specification)
-                subscription = isinstance(key, tuple) and key[0] == 's'
-                if subscription:
-                    # v is tuple of subs
-                    implied[key] = implied.get(key, ()) + v
-                else:
-                    oldbyname = implied.get(key)
-                    if not oldbyname:
-                        implied[key] = oldbyname = {}
-                    
-                    # v is name -> object
-                    oldbyname.update(v)
+        return result
 
-            for key, v in ancestor.multImplied.iteritems():
-                # key is (specification, order)
-                #     or ('s', specification, order)
-                subscription = key[0] == 's'
-                if subscription:
-                    oldwithobs = implied.get(key)
-                    if not oldwithobs:
-                        oldwithobs = implied[key] = {}
-                        
-                    # v is {with -> tuple([object])}
-                    for with, objects in v.iteritems():
-                        oldwithobs[with] = oldwithobs.get(with, ()) + objects
-                    
-                else:
-                    oldbyname = implied.get(key)
-                    if not oldbyname:
-                        implied[key] = oldbyname = {}
-
-                    # v is {name -> {with -> ?}}
-                    for name, withobs in v.iteritems():
-                        oldwithobs = oldbyname.get(name)
-                        if not oldwithobs:
-                            oldwithobs = oldbyname[name] = {}
-
-                        # withobs is {with -> object}
-                        oldwithobs.update(withobs)
-
-        # Now flatten with mappings to tuples
-        for key, v in implied.iteritems():
-            if isinstance(key, tuple):
-                if key[0] == 's':
-                    # subscriptions
-                    if isinstance(v, dict):
-                        implied[key] = v.items()
-                else:
-                    byname = v
-                    for name, value in byname.iteritems():
-                        if isinstance(value, dict):
-                            # We have {with -> value}
-                            # convert it to sorted [(with, value]
-                            byname[name] = orderwith(value)
-
-        self.get = implied.get
-
-    def get(self, key):
-        """Get an implied value
-
-        This is only called when the surrogate is dirty
-        """
-        self.clean()
-        return self.__dict__['get'](key)
-
-    def selfImplied(self):
-        """Return selfImplied when dirty
-        """
-        self.clean()
-        return self.__dict__['selfImplied']
-    selfImplied = ReadProperty(selfImplied)
-
-    def multiImplied(self):
-        """Return _multiImplied when dirty
-        """
-        self.clean()
-        return self.__dict__['multiImplied']
-    multiImplied = ReadProperty(multiImplied)
-
-    def subscribe(self, dependent):
-        self.dependents[dependent] = 1
-
-    def unsubscribe(self, dependent):
-        del self.dependents[dependent]
-
-    def _adaptTo(self, specification, object, name='', with=()):
-        if object is None:
-            try:
-                del self.adapters[False, tuple(with), name, specification]
-            except KeyError:
-                pass
+    def subscribers(self, objects, provided, name=u''):
+        if provided is None:
+            result = ()
         else:
-            self.adapters[False, tuple(with), name, specification
-                          ] = object
-
-        self.dirty()
-
-    def _subscriptionAdaptTo(self, specification, object, with=()):
-        if object is None:
-            raise TypeError, ("Unregistering subscription adapters" 
-                              " isn't implemented")
-
-        key = (True, tuple(with), '', specification)
-        self.adapters[key] = self.adapters.get(key, ()) + (object, )
-        self.dirty()
-
-    def changed(self, which=None):
-        self.dirty()
-
-    def __repr__(self):
-        return '<%s(%s)>' % (self.__class__.__name__, self.spec())
-
-def orderwith(bywith):
-
-    # Convert {with -> adapter} to withs, [(with, value)]
-    # such that there are no i, j, i < j, such that
-    #           withs[j][0] extends withs[i][0].
-
-    withs = []
-    for with, value in bywith.iteritems():
-        for i, (w, v) in enumerate(withs):
-            if withextends(with, w):
-                withs.insert(i, (with, value))
-                break
-        else:
-            withs.append((with, value))
+            result = []
             
-    return withs
-    
-
-def withextends(with1, with2):
-    for spec1, spec2 in zip(with1, with2):
-        if spec1.extends(spec2):
-            return True
-        if spec1 != spec2:
-            break
-    return False
-
-
-class AdapterLookup(object):
-    # Adapter lookup support
-    # We have a class here because we want to provide very
-    # fast lookup support in C and making this part of the adapter
-    # registry itself would provide problems if someone wanted
-    # persistent adapter registries, because we want C slots for fast
-    # lookup that would clash with persistence-supplied slots.
-    # so this class acts a little bit like a lookup adapter for the adapter
-    # registry.
-
-    def __init__(self, registry, surrogates, _remove):
-        self._registry = registry
-        self._surrogateClass = registry._surrogateClass
-        self._default = registry._default
-        self._null = registry._null
-        self._surrogates = surrogates
-        self._remove = _remove
-
-    def lookup(self, required, provided, name='', default=None):
-        order = len(required)
-        if order == 1:
-            # Simple adapter:
-            s = self.get(required[0])
-            byname = s.get(provided)
-            if byname:
-                value = byname.get(name)
+        for self in self.ro:
+            if name:
+                byorder = self._named_subscriptions.get(name)
+                if byorder is None:
+                    continue
             else:
-                value = None
+                byorder = self._unnamed_subscriptions
 
-            if value is None:
-                byname = self._default.get(provided)
-                if byname:
-                    value = byname.get(name, default)
-                else:
-                    return default
-                
-            return value
-
-        elif order == 0:
-            # null adapter
-            byname = self._null.get(provided)
-            if byname:
-                return byname.get(name, default)
-            else:
-                return default
-
-        # Multi adapter
-
-        with = required[1:]
-        key = provided, order
-
-        for surrogate in self.get(required[0]), self._default:
-            byname = surrogate.get(key)
-            if not byname:
+            order = len(objects)
+            if order >= len(byorder):
                 continue
 
-            bywith = byname.get(name)
-            if not bywith:
-                continue
+            subscribers(byorder[order].components, objects, provided, result)
 
-            # 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.
+        return result
 
-            # `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:
-                    # 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]
+def _normalize_name(name):
+    if isinstance(name, basestring):
+        return unicode(name)
 
-        return default
+    raise TypeError("name must be a regular or unicode string")
 
-    def lookup1(self, required, provided, name='', default=None):
-        return self.lookup((required,), provided, name, default)
-
-    def adapter_hook(self, interface, object, name='', default=None):
-        """Hook function used when calling interfaces.
-
-        When called from Interface.__adapt__, only the interface and
-        object parameters will be passed.
-
-        If the factory produces `None`, then the default is returned. This
-        allows us to prevent adaptation (if desired) and make the factory
-        decide whether an adapter will be available.
-        """
-        factory = self.lookup1(providedBy(object), interface, name)
-        if factory is not None:
-            adapter = factory(object)
-            if adapter is not None:
-                return adapter
-        return default
-
-    def queryAdapter(self, object, interface, name='', default=None):
-        # Note that we rarely call queryAdapter directly
-        # We usually end up calling adapter_hook
-        return self.adapter_hook(interface, object, name, default)
-
-    def subscriptions(self, required, provided):
-        if provided is None:
-            provided = Null
-
-        order = len(required)
-        if order == 1:
-            # Simple subscriptions:
-            s = self.get(required[0])
-            result = s.get(('s', provided))
-            if result:
-                result = list(result)
-            else:
-                result = []
-
-            default = self._default.get(('s', provided))
-            if default:
-                result.extend(default)
-                
-            return result
-
-        elif order == 0:
-            result = self._null.get(('s', provided))
-            if result:
-                return list(result)
-            else:
-                return []
         
-        # Multi
-        key = 's', provided, order
-        with = required[1:]
-        result = []
-        
-        for surrogate in self.get(required[0]), self._default:
-            bywith = surrogate.get(key)
-            if not bywith:
-                continue
+class Next:
 
-            for rwith, values in bywith:
-                for rspec, spec in zip(rwith, with):
-                    if not spec.isOrExtends(rspec):
-                        break # This one is no good
-                else:
-                    # we didn't break, so we have a match
-                    result.extend(values)
-
-        return result
-
+    def __init__(self, spec, basis):
+        sro = spec.__sro__
+        self.__sro__ = sro[sro.index(basis)+1:]
         
 
-    def queryMultiAdapter(self, objects, interface, name='', default=None):
-        factory = self.lookup(map(providedBy, objects), interface, name)
-        if factory is not None:
-            return factory(*objects)
+class Adapters(object):
 
-        return default
+    def __init__(self):
+        self.components = {}
+        self.provided = {} # {iface -> (iro, [(required, value)])}
 
-    def subscribers(self, objects, interface):
-        subscriptions = self.subscriptions(map(providedBy, objects), interface)
-        subscribers = [subscription(*objects)
-                       for subscription in subscriptions]
-        # Filter None values
-        return [x for x in subscribers if x is not None]
+    def register(self, required, provided, value):
+        if (provided is None) or (provided is Interface):
+            self._register(required, provided, provided, value)
+        else:
+            registered = self.provided.get(provided)
+            if registered is None:
+                self.provided[provided] = registered = provided.__iro__, []
+                provided.subscribe(self)
+            registered[1].append((required, value))
 
-    def get(self, declaration):
-        if declaration is None:
-            return self._default
+            for p in provided.__iro__:
+                self._register(required, provided, p, value)
 
-        ref = declaration.weakref(self._remove)
-        surrogate = self._surrogates.get(ref)
-        if surrogate is None:
-            surrogate = self._surrogateClass(declaration, self._registry)
-            self._surrogates[ref] = surrogate
+    def _register(self, required, provided, p, value):
+        d = self.components
+        k = p
+        for r in required:
+            if r is None:
+                r = Interface
+            v = d.get(k)
+            if v is None:
+                d[k] = v = {}
+            d = v
+            k = r
 
-        return surrogate
+        components = d.get(k, ())
+        d[k] = self._add(components, provided, value)
 
-
-class AdapterRegistry(object):
-    """Adapter registry
-    """
-
-    # Implementation note:
-    # We are like a weakref dict ourselves. We can't use a weakref
-    # dict because we have to use spec.weakref() rather than
-    # weakref.ref(spec) to get weak refs to specs.
-
-    _surrogateClass = Surrogate
-
-    def __init__(self):
-        default = self._surrogateClass(Default, self)
-        self._default = default
-        null = self._surrogateClass(Null, self)
-        self._null = null
-
-        # Create separate lookup object and copy it's methods
-        surrogates = {Default.weakref(): default, Null.weakref(): null}
-        def _remove(k):
-            try:
-                del surrogates[k]
-            except KeyError:
-                pass
-        lookup = AdapterLookup(self, surrogates, _remove)
+    def _add(self, components, provided, value):
+        if provided is None:
+            return components + ((value, provided), )
         
-        for name in ('lookup', 'lookup1', 'queryAdapter', 'get',
-                     'adapter_hook', 'subscriptions',
-                     'queryMultiAdapter', 'subscribers',
-                     ):
-            setattr(self, name, getattr(lookup, name))
-
-    def register(self, required, provided, name, value):
-        if required:
-            with = []
-            for iface in required[1:]:
-                if iface is None:
-                    iface = Interface
-                with.append(iface)
-            with = tuple(with)
-            required = self.get(required[0])
-        else:
-            with = ()
-            required = self._null
+        return (
+            tuple([c for c in components if provided.extends(c[1])])
+            +
+            ((value, provided), )
+            +
+            tuple([c for c in components if not provided.extends(c[1])])
+            )
         
-        if not isinstance(name, basestring):
-            raise TypeError("The name provided to provideAdapter "
-                            "must be a string or unicode")
+    def unregister(self, required, provided, value):
+        if (provided is None) or (provided is Interface):
+            self._unregister(required, provided, provided, value)
+        else:
+            registered = self.provided.get(provided)
+            if registered is None:
+                return
+            if value is None:
+                rv = [r for r in registered[1] if r[0] != required]
+            else:
+                rv = [r for r in registered[1] if r != (required, value)]
 
-        required._adaptTo(provided, value, unicode(name), with)
+            if rv:
+                self.provided[provided] = registered[0], rv
+            else:
+                del self.provided[provided]
 
-    def lookupAll(self, required, provided):
-        order = len(required)
-        if order == 1:
-            # Simple adapter:
-            s = self.get(required[0])
-            byname = s.get(provided)
-            if byname:
-                for item in byname.iteritems():
-                    yield item
+            for p in provided.__iro__:
+                self._unregister(required, provided, p, value)
 
-            defbyname = self._default.get(provided)
-            if defbyname:
-                for name, value in defbyname.iteritems():
-                    if name in byname:
-                        continue
-                    yield name, value
+    def _unregister(self, required, provided, p, value):
+        items = []
+        d = self.components
+        k = p
+        for r in required:
+            if r is None:
+                r = Interface
+            v = d.get(k)
+            if v is None:
+                return
+            items.append((d, k))
+            d = v
+            k = r
 
+        components = d.get(k, None)
+        if components is None:
             return
 
-        elif order == 0:
-            # null adapter
-            byname = self._null.get(provided)
-            if byname:
-                for item in byname.iteritems():
-                    yield item
-
-            return
-
-
-        # Multi adapter
-
-        with = required[1:]
-        key = provided, order
-        first = ()
-
-        for surrogate in self.get(required[0]), self._default:
-            byname = surrogate.get(key)
-            if not byname:
-                continue
-
-            for name, bywith in byname.iteritems():
-                if not bywith or name in first:
-                    continue
-
-                # See comments on lookup() above
-                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:
-                        # 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:
-                    yield name, best[1]
-
-            first = byname
-
-    def subscribe(self, required, provided, value):
-        if required:
-            required, with = self.get(required[0]), tuple(required[1:])
+        if value is None:
+            # unregister all
+            components = [c for c in components
+                          if c[1] != provided]
         else:
-            required = self._null
-            with = ()
+            # unregister just this one
+            components = [c for c in components
+                          if c != (value, provided)]
 
-        if provided is None:
-            provided = Null
-            
-        required._subscriptionAdaptTo(provided, value, with)
-
-def mextends(with, rwith):
-    if len(with) == len(rwith):
-        for w, r in zip(with, rwith):
-            if not w.isOrExtends(r):
-                break
+        if components:
+            d[k] = tuple(components)
         else:
-            return True
-    return False
+            del d[k]
 
-def adapterImplied(adapters):
-    implied = {}
-    multi = {}
+            items.reverse()
+            for d, k in items:
+                if not d[k]:
+                    del d[k]
 
-    # This dictionary is used to catch situations specific adapters
-    # override less specific adapters.
-    # Because subscriptions are cumulative, registered doesn't apply.
-    registered = {}
+class Subscriptions(Adapters):
 
-    # Add adapters and interfaces directly implied by same:
+    def _add(self, components, provided, value):
+        return components + ((value, provided), )
 
-    for key, value in adapters.iteritems():
-
-        # TODO: Backward compatibility
-        # BBB ? Don't need to handle 3-tuples some day
-        try:
-            (subscription, with, name, target) = key
-        except ValueError:
-            (with, name, target) = key
-            subscription = False
-
-        if subscription:
-            if with:
-                _add_multi_sub_adapter(with, target, multi, value)
-            else:
-                _add_named_sub_adapter(target, implied, value)
-        else:
-            if with:
-                _add_multi_adapter(with, name, target, target, multi,
-                                   registered, value)
-            else:
-                _add_named_adapter(target, target, name, implied,
-                                   registered, value)
-
-    return implied, multi
-
-def _add_named_adapter(target, provided, name, implied,
-                       registered, value):
+def _lookup(components, specs, i, l):
+    if i < l:
+        for spec in specs[i].__sro__:
+            comps = components.get(spec)
+            if comps is not None:
+                r = _lookup(comps, specs, i+1, l)
+                if r is not None:
+                    return r
+        return None
     
-    ikey = target
-    rkey = target, name
+    return components
 
-    byname = implied.get(ikey)
-    if not byname:
-        byname = implied[ikey] = {}
+def lookup(components, required, provided):
+    components = components.get(provided)
+    if components:
 
-    if (name not in byname
-        or
-        (rkey in registered and registered[rkey].extends(provided))
-        ):
+        if required:
+            components = _lookup(components, required, 0, len(required))
+            if not components:
+                return None
 
-        registered[rkey] = provided
-        byname[name] = value
+        return components[0][0]
 
-        for b in target.__bases__:
-            _add_named_adapter(b, provided, name, implied,
-                               registered, value)
+    return None
 
-def _add_multi_adapter(with, name, target, provided, implied,
-                       registered, object):
+def lookup1(components, required, provided):
+    components = components.get(provided)
+    if components:
+        for s in required.__sro__:
+            comps = components.get(s)
+            if comps:
+                return comps[0][0]
 
-    ikey = target, (len(with) + 1)
-    byname = implied.get(ikey)
-    if not byname:
-        byname = implied[ikey] = {}
+    return None
 
-    bywith = byname.get(name)
-    if not bywith:
-        bywith = byname[name] = {}
+def _subscribers(components, specs, i, l, objects, result):
+    if i < l:
+        sro = list(specs[i].__sro__)
+        sro.reverse()
+        for spec in sro:
+            comps = components.get(spec)
+            if comps is not None:
+                _subscribers(comps, specs, i+1, l, objects, result)
+    else:
+        if objects is None:
+            result.extend([c[0] for c in components])
+        else:
+            for c in components:
+                c = c[0](*objects)
+                if c is not None and result is not None:
+                    result.append(c)
 
-    
-    rkey = ikey, name, with # The full key has all 4
-    if (with not in bywith
-        or
-        (rkey not in registered or registered[rkey].extends(provided))
-        ):
-        # This is either a new entry or it is an entry for a more
-        # general interface that is closer provided than what we had
-        # before
-        registered[rkey] = provided
-        bywith[with] = object
+def subscriptions(components, required, provided, result):
+    components = components.get(provided)
+    if components:
+        _subscribers(components, required, 0, len(required), None, result)
 
-    for b in target.__bases__:
-        _add_multi_adapter(with, name, b, provided, implied,
-                           registered, object)
+def subscribers(components, objects, provided, result):
+    components = components.get(provided)
+    if components:
+        required = map(providedBy, objects)
 
-def _add_named_sub_adapter(target, implied, objects):
-    key = ('s', target)
-    implied[key] = implied.get(key, ()) + objects
-    
-    for b in target.__bases__:
-        _add_named_sub_adapter(b, implied, objects)
+        if provided is None:
+            result == None
 
-def _add_multi_sub_adapter(with, target, implied, objects):
-    key = 's', target, (len(with) + 1)
-    bywith = implied.get(key)
-    if not bywith:
-        bywith = implied[key] = {}
+        _subscribers(components, required, 0, len(required), objects, result)
 
-    bywith[with] = bywith.get(with, ()) + objects
-
-    for b in target.__bases__:
-        _add_multi_sub_adapter(with, b, implied, objects)
+try:
+    from _zope_interface_coptimizations import lookup, lookup1
+    from _zope_interface_coptimizations import subscribers, subscriptions
+except ImportError:
+    pass
+    

Modified: Zope3/branches/jim-adapter-redesign/src/zope/interface/adapter.txt
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/interface/adapter.txt	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/interface/adapter.txt	2005-09-08 10:17:23 UTC (rev 38384)
@@ -382,6 +382,9 @@
 Subscriptions
 =============
 
+XXX need tests that demonstrate that more general subscribers are
+    called before more specific subscribers
+
 Normally, we want to look up an object that most-closely matches a
 specification.  Sometimes, we want to get all of the objects that
 match some specification.  We use subscriptions for this.  We
@@ -452,7 +455,7 @@
 
 You can have subscriptions that are indepenent of any specifications::
   
-  >>> registry.subscriptions([], IP1)
+  >>> list(registry.subscriptions([], IP1))
   []
 
   >>> registry.subscribe([], IP2, 'sub2')

Modified: Zope3/branches/jim-adapter-redesign/src/zope/interface/declarations.py
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/interface/declarations.py	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/interface/declarations.py	2005-09-08 10:17:23 UTC (rev 38384)
@@ -237,22 +237,7 @@
 
     __radd__ = __add__
 
-    def __nonzero__(self):
-        """Test whether there are any interfaces in a specification.
 
-        >>> from zope.interface import Interface
-        >>> class I1(Interface): pass
-        ...
-        >>> spec = Declaration(I1)
-        >>> int(bool(spec))
-        1
-        >>> spec = Declaration()
-        >>> int(bool(spec))
-        0
-        """
-        return bool(self.__iro__)
-
-
 ##############################################################################
 #
 # Implementation specifications
@@ -1216,31 +1201,6 @@
         1
 
 
-        nonzero:
-
-        >>> from zope.interface import Interface
-        >>> class I1(Interface):
-        ...     pass
-        >>> class I2(Interface):
-        ...     pass
-        >>> class C(object):
-        ...     implements(I1)
-        >>> c = C()
-        >>> int(bool(providedBy(c)))
-        1
-        >>> directlyProvides(c, I2)
-        >>> int(bool(providedBy(c)))
-        1
-        >>> class C(object):
-        ...     pass
-        >>> c = C()
-        >>> int(bool(providedBy(c)))
-        0
-        >>> directlyProvides(c, I2)
-        >>> int(bool(providedBy(c)))
-        1
-
-
     """
 
     return Provides(cls, direct)

Modified: Zope3/branches/jim-adapter-redesign/src/zope/interface/interface.py
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/interface/interface.py	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/interface/interface.py	2005-09-08 10:17:23 UTC (rev 38384)
@@ -137,7 +137,7 @@
           ...
           >>> spec = Declaration()
           >>> int(spec.extends(Interface))
-          0
+          1
           >>> spec = Declaration(I2)
           >>> int(spec.extends(Interface))
           1
@@ -160,6 +160,8 @@
 except ImportError:
     pass
 
+
+
 class Specification(SpecificationBase):
     """Specifications
 
@@ -262,10 +264,17 @@
         implied.clear()
 
         ancestors = ro(self)
+
+        try:
+            if Interface not in ancestors:
+                ancestors.append(Interface)
+        except NameError:
+            pass # defining Interface itself
+
         self.__sro__ = tuple(ancestors)
         self.__iro__ = tuple([ancestor for ancestor in ancestors
                               if isinstance(ancestor, InterfaceClass)
-                             ])
+                              ])
 
         for ancestor in ancestors:
             # We directly imply our ancestors:
@@ -330,7 +339,7 @@
           ...
           >>> spec = Declaration()
           >>> int(spec.extends(Interface))
-          0
+          1
           >>> spec = Declaration(I2)
           >>> int(spec.extends(Interface))
           1
@@ -938,8 +947,9 @@
     from zope.interface.interfaces import IMethod
     classImplements(Method, IMethod)
 
-    from zope.interface.interfaces import IInterface
+    from zope.interface.interfaces import IInterface, ISpecification
     classImplements(InterfaceClass, IInterface)
+    classImplements(Specification, ISpecification)
 
 # We import this here to deal with module dependencies.
 from zope.interface.declarations import providedBy, implementedBy

Modified: Zope3/branches/jim-adapter-redesign/src/zope/interface/interfaces.py
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/interface/interfaces.py	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/interface/interfaces.py	2005-09-08 10:17:23 UTC (rev 38384)
@@ -645,13 +645,32 @@
         provided interface, and a name.
         """
 
-    def lookup(required, provided, name, default=None):
+    def lookup(required, provided, name='', default=None):
         """Lookup a value
 
         A value is looked up based on a *sequence* of required
         specifications, a provided interface, and a name.
         """
 
+    def queryMultiAdapter(objects, provided, name=u'', default=None):
+        """Adapt a sequence of objects to a named, provided, interface
+        """
+
+    def lookup1(required, provided, name=u'', default=None):
+        """Lookup a value using a single required interface
+
+        A value is looked up based on a single required
+        specifications, a provided interface, and a name.
+        """
+
+    def queryAdapter(object, provided, name=u'', default=None):
+        """Adapt an object using a registered adapter factory.
+        """
+
+    def adapter_hook(provided, object, name=u'', default=None):
+        """Adapt an object using a registered adapter factory.
+        """
+
     def lookupAll(required, provided):
         """Find all adapters from the required to the provided interfaces
 
@@ -662,7 +681,7 @@
         """Return the names for which there are registered objects
         """
 
-    def subscribe(required, provided, subscriber):
+    def subscribe(required, provided, subscriber, name=u''):
         """Register a subscriber
 
         A subscriber is registered for a *sequence* of required
@@ -672,10 +691,13 @@
         equivalent) interfaces.
         """
 
-    def subscriptions(required, provided):
+    def subscriptions(required, provided, name=u''):
         """Get a sequence of subscribers
 
         Subscribers for a *sequence* of required interfaces, and a provided
         interface are returned.
         """
     
+    def subscribers(objects, provided, name=u''):
+        """Get a sequence of subscription adapters
+        """

Modified: Zope3/branches/jim-adapter-redesign/src/zope/interface/tests/test_adapter.py
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/interface/tests/test_adapter.py	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/interface/tests/test_adapter.py	2005-09-08 10:17:23 UTC (rev 38384)
@@ -36,23 +36,7 @@
     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()

Modified: Zope3/branches/jim-adapter-redesign/src/zope/security/checker.py
===================================================================
--- Zope3/branches/jim-adapter-redesign/src/zope/security/checker.py	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/src/zope/security/checker.py	2005-09-08 10:17:23 UTC (rev 38384)
@@ -568,6 +568,7 @@
     complex: NoProxy,
     types.NoneType: NoProxy,
     str: NoProxy,
+    tuple: NoProxy,
     unicode: NoProxy,
     type(True): NoProxy, # Boolean, if available :)
     datetime.timedelta: NoProxy,
@@ -621,9 +622,9 @@
     sets.ImmutableSet: _setChecker,
 
     # YAGNI: () a rock
-    tuple: NamesChecker(['__getitem__', '__getslice__', '__add__', '__radd__',
-                         '__contains__', '__len__', '__iter__',
-                         '__str__']),
+##     tuple: NamesChecker(['__getitem__', '__getslice__', '__add__', '__radd__',
+##                          '__contains__', '__len__', '__iter__',
+##                          '__str__']),
     types.InstanceType: _instanceChecker,
     Proxy: NoProxy,
     type(weakref.ref(_Sequence())): NamesChecker(['__call__']),

Modified: Zope3/branches/jim-adapter-redesign/z3.py
===================================================================
--- Zope3/branches/jim-adapter-redesign/z3.py	2005-09-08 10:17:17 UTC (rev 38383)
+++ Zope3/branches/jim-adapter-redesign/z3.py	2005-09-08 10:17:23 UTC (rev 38384)
@@ -23,7 +23,7 @@
 
 def run(argv=list(sys.argv)):
 
-    if sys.version_info < ( 2,3,5 ):
+    if sys.version_info < ( 2,3,4 ):
         print """\
         ERROR: Your python version is not supported by Zope3.
         Zope3 needs Python 2.3.5 or greater. You are running:""" + sys.version



More information about the Zope3-Checkins mailing list