[Checkins] SVN: grok/trunk/src/grok/ implemented grok.provides (specify which interface to use in ambiguous cases) for Adapter, MultiAdapter and GlobalUtility

Wolfgang Schnerring wosc at wosc.de
Sat Jan 6 09:58:48 EST 2007


Log message for revision 71735:
  implemented grok.provides (specify which interface to use in ambiguous cases) for Adapter, MultiAdapter and GlobalUtility

Changed:
  U   grok/trunk/src/grok/__init__.py
  U   grok/trunk/src/grok/directive.py
  U   grok/trunk/src/grok/interfaces.py
  U   grok/trunk/src/grok/meta.py
  U   grok/trunk/src/grok/tests/adapter/adapter.py
  U   grok/trunk/src/grok/tests/adapter/implementsmany.py
  U   grok/trunk/src/grok/tests/adapter/implementsnone.py
  U   grok/trunk/src/grok/tests/adapter/implementsnonemulti.py
  U   grok/trunk/src/grok/tests/adapter/multiadapter.py
  A   grok/trunk/src/grok/tests/utility/implementsmany.py
  U   grok/trunk/src/grok/tests/utility/implementsnone.py
  U   grok/trunk/src/grok/tests/utility/utility.py
  U   grok/trunk/src/grok/util.py

-=-
Modified: grok/trunk/src/grok/__init__.py
===================================================================
--- grok/trunk/src/grok/__init__.py	2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/__init__.py	2007-01-06 14:58:47 UTC (rev 71735)
@@ -33,7 +33,7 @@
 from grok.components import Model, Adapter, MultiAdapter, View, XMLRPC
 from grok.components import PageTemplate, GlobalUtility, Container, Traverser, Site
 from grok.components import EditForm, DisplayForm, AddForm
-from grok.directive import context, name, template, templatedir
+from grok.directive import context, name, template, templatedir, provides
 from grok._grok import do_grok as grok  # Avoid name clash within _grok
 from grok._grok import SubscribeDecorator as subscribe
 from grok.error import GrokError, GrokImportError

Modified: grok/trunk/src/grok/directive.py
===================================================================
--- grok/trunk/src/grok/directive.py	2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/directive.py	2007-01-06 14:58:47 UTC (rev 71735)
@@ -112,10 +112,20 @@
             raise GrokImportError("You can only pass classes or interfaces to "
                                   "%s." % self.name)
 
+class InterfaceDirective(Directive):
+    """
+    Directive that only accepts interface values.
+    """
 
+    def check(self, value):
+        if not (IInterface.providedBy(value)):
+            raise GrokImportError("You can only pass interfaces to "
+                                  "%s." % self.name)
+
 # Define grok directives
 name = TextDirective('grok.name', ClassDirectiveContext())
 template = TextDirective('grok.template', ClassDirectiveContext())
 context = InterfaceOrClassDirective('grok.context',
                                     ClassOrModuleDirectiveContext())
 templatedir = TextDirective('grok.templatedir', ModuleDirectiveContext())
+provides = InterfaceDirective('grok.provides', ClassDirectiveContext())

Modified: grok/trunk/src/grok/interfaces.py
===================================================================
--- grok/trunk/src/grok/interfaces.py	2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/interfaces.py	2007-01-06 14:58:47 UTC (rev 71735)
@@ -79,6 +79,10 @@
         of the directory.  This can be overridden using
         ``templatedir``."""
 
+    def provides(interface):
+        """Explicitly specify with which interface a component will be looked up.
+        """
+
 class IGrokDecorators(interface.Interface):
 
     def subscribe(*classes_or_interfaces):

Modified: grok/trunk/src/grok/meta.py
===================================================================
--- grok/trunk/src/grok/meta.py	2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/meta.py	2007-01-06 14:58:47 UTC (rev 71735)
@@ -33,30 +33,34 @@
 
     def register(self, context, name, factory, module_info, templates):
         adapter_context = util.determine_class_context(factory, context)
-        util.check_implements_one(factory)
+        provides = util.class_annotation(factory, 'grok.provides', None)
+        if provides is None:
+            util.check_implements_one(factory)
         name = util.class_annotation(factory, 'grok.name', '')
-        try:
-            component.provideAdapter(factory, adapts=(adapter_context,),
-                                     name=name)
-        except TypeError:
-            import pdb; pdb.set_trace()
+        component.provideAdapter(factory, adapts=(adapter_context,),
+                                 provides=provides,
+                                 name=name)
             
 class MultiAdapterGrokker(grok.ClassGrokker):
     component_class = grok.MultiAdapter
     
     def register(self, context, name, factory, module_info, templates):
-        util.check_implements_one(factory)
+        provides = util.class_annotation(factory, 'grok.provides', None)
+        if provides is None:
+            util.check_implements_one(factory)
         util.check_adapts(factory)
         name = util.class_annotation(factory, 'grok.name', '')
-        component.provideAdapter(factory, name=name)
+        component.provideAdapter(factory, provides=provides, name=name)
 
 class GlobalUtilityGrokker(grok.ClassGrokker):
     component_class = grok.GlobalUtility
 
     def register(self, context, name, factory, module_info, templates):
-        util.check_implements_one(factory)
+        provides = util.class_annotation(factory, 'grok.provides', None)
+        if provides is None:
+            util.check_implements_one(factory)
         name = util.class_annotation(factory, 'grok.name', '')
-        component.provideUtility(factory(), name=name)
+        component.provideUtility(factory(), provides=provides, name=name)
 
 class XMLRPCGrokker(grok.ClassGrokker):
     component_class = grok.XMLRPC

Modified: grok/trunk/src/grok/tests/adapter/adapter.py
===================================================================
--- grok/trunk/src/grok/tests/adapter/adapter.py	2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/tests/adapter/adapter.py	2007-01-06 14:58:47 UTC (rev 71735)
@@ -8,6 +8,12 @@
   True
   >>> isinstance(home, Home)
   True
+
+  >>> fireplace = IFireplace(cave)
+  >>> IFireplace.providedBy(fireplace)
+  True
+  >>> isinstance(fireplace, Fireplace)
+  True
 """
 
 import grok
@@ -21,3 +27,10 @@
 
 class Home(grok.Adapter):
     grok.implements(IHome)
+
+class IFireplace(interface.Interface):
+    pass
+
+class Fireplace(grok.Adapter):
+    grok.implements(IFireplace, IHome)
+    grok.provides(IFireplace)

Modified: grok/trunk/src/grok/tests/adapter/implementsmany.py
===================================================================
--- grok/trunk/src/grok/tests/adapter/implementsmany.py	2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/tests/adapter/implementsmany.py	2007-01-06 14:58:47 UTC (rev 71735)
@@ -5,7 +5,8 @@
   >>> grok.grok(__name__)
   Traceback (most recent call last):
     ...
-  GrokError: <class 'grok.tests.adapter.implementsmany.Home'> must implement exactly one interface (use grok.implements to specify).
+  GrokError: <class 'grok.tests.adapter.implementsmany.Home'> is implementing
+  more than one interface (use grok.provides to specify which one to use).
 """
 import grok
 

Modified: grok/trunk/src/grok/tests/adapter/implementsnone.py
===================================================================
--- grok/trunk/src/grok/tests/adapter/implementsnone.py	2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/tests/adapter/implementsnone.py	2007-01-06 14:58:47 UTC (rev 71735)
@@ -6,7 +6,7 @@
   Traceback (most recent call last):
     ...
   GrokError: <class 'grok.tests.adapter.implementsnone.Home'> must
-  implement exactly one interface (use grok.implements to specify).
+  implement at least one interface (use grok.implements to specify).
 """
 import grok
 

Modified: grok/trunk/src/grok/tests/adapter/implementsnonemulti.py
===================================================================
--- grok/trunk/src/grok/tests/adapter/implementsnonemulti.py	2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/tests/adapter/implementsnonemulti.py	2007-01-06 14:58:47 UTC (rev 71735)
@@ -6,7 +6,7 @@
   Traceback (most recent call last):
     ...
   GrokError: <class 'grok.tests.adapter.implementsnonemulti.Home'> must
-  implement exactly one interface (use grok.implements to specify).
+  implement at least one interface (use grok.implements to specify).
 """
 import grok
 

Modified: grok/trunk/src/grok/tests/adapter/multiadapter.py
===================================================================
--- grok/trunk/src/grok/tests/adapter/multiadapter.py	2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/tests/adapter/multiadapter.py	2007-01-06 14:58:47 UTC (rev 71735)
@@ -32,6 +32,20 @@
   True
   >>> home.fireplace is fireplace
   True
+
+Multiadapters that implement more than one interface can use grok.provides to
+specify the one to use:
+
+  >>> home = component.getMultiAdapter((cave, fireplace), name='home3')
+
+  >>> IHome.providedBy(home)
+  True
+  >>> isinstance(home, Home3)
+  True
+  >>> home.cave is cave
+  True
+  >>> home.fireplace is fireplace
+  True
 """
 
 import grok
@@ -62,3 +76,16 @@
     def __init__(self, cave, fireplace):
         self.cave = cave
         self.fireplace = fireplace
+
+class IFireplace(interface.Interface):
+    pass
+
+class Home3(grok.MultiAdapter):
+    grok.adapts(Cave, Fireplace)
+    grok.implements(IHome, IFireplace)
+    grok.provides(IHome)
+    grok.name('home3')
+
+    def __init__(self, cave, fireplace):
+        self.cave = cave
+        self.fireplace = fireplace

Added: grok/trunk/src/grok/tests/utility/implementsmany.py
===================================================================
--- grok/trunk/src/grok/tests/utility/implementsmany.py	2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/tests/utility/implementsmany.py	2007-01-06 14:58:47 UTC (rev 71735)
@@ -0,0 +1,21 @@
+"""
+Subclasses of grok.GlobalUtility that implement more than one interface must
+specify which interface to use for the registration:
+
+  >>> grok.grok(__name__)
+  Traceback (most recent call last):
+    ...
+  GrokError: <class 'grok.tests.utility.implementsmany.Club'> is implementing
+  more than one interface (use grok.provides to specify which one to use).
+"""
+import grok
+from zope import interface
+
+class IClub(interface.Interface):
+    pass
+
+class ISpikyClub(interface.Interface):
+    pass
+
+class Club(grok.GlobalUtility):
+    grok.implements(IClub, ISpikyClub)

Modified: grok/trunk/src/grok/tests/utility/implementsnone.py
===================================================================
--- grok/trunk/src/grok/tests/utility/implementsnone.py	2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/tests/utility/implementsnone.py	2007-01-06 14:58:47 UTC (rev 71735)
@@ -5,7 +5,7 @@
   Traceback (most recent call last):
     ...
   GrokError: <class 'grok.tests.utility.implementsnone.Club'> must
-  implement exactly one interface (use grok.implements to specify).
+  implement at least one interface (use grok.implements to specify).
 """
 import grok
 

Modified: grok/trunk/src/grok/tests/utility/utility.py
===================================================================
--- grok/trunk/src/grok/tests/utility/utility.py	2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/tests/utility/utility.py	2007-01-06 14:58:47 UTC (rev 71735)
@@ -17,6 +17,27 @@
   True
   >>> isinstance(huge_club, HugeClub)
   True
+
+A utility can explicitly specify which interface it should be looked up with.
+
+  >>> spiky_club = component.getUtility(IClub, name='spiky')
+  >>> isinstance(spiky_club, SpikyClub)
+  True
+
+  >>> component.getUtility(ISpikyClub, name='spiky')
+  Traceback (most recent call last):
+    ...
+  ComponentLookupError: (<InterfaceClass grok.tests.utility.utility.ISpikyClub>,
+                         'spiky')
+
+If a utility implements more than one interface, it has to specify the one to
+use with 'grok.provides':
+
+  >>> nightclub = component.getUtility(INightClub)
+  >>> INightClub.providedBy(nightclub)
+  True
+  >>> isinstance(nightclub, NightClub)
+  True
 """
 import grok
 
@@ -25,9 +46,24 @@
 class IClub(interface.Interface):
     pass
 
+class ISpikyClub(IClub):
+    pass
+
+class INightClub(interface.Interface):
+    pass
+
 class NormalClub(grok.GlobalUtility):
     grok.implements(IClub)
 
 class HugeClub(grok.GlobalUtility):
     grok.implements(IClub)
     grok.name('huge')    
+
+class SpikyClub(grok.GlobalUtility):
+    grok.implements(ISpikyClub)
+    grok.provides(IClub)
+    grok.name('spiky')
+
+class NightClub(grok.GlobalUtility):
+    grok.implements(INightClub, ISpikyClub)
+    grok.provides(INightClub)

Modified: grok/trunk/src/grok/util.py
===================================================================
--- grok/trunk/src/grok/util.py	2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/util.py	2007-01-06 14:58:47 UTC (rev 71735)
@@ -71,10 +71,14 @@
 
 
 def check_implements_one(class_):
-    if len(list(interface.implementedBy(class_))) != 1:
-        raise GrokError("%r must implement exactly one interface "
+    if len(list(interface.implementedBy(class_))) < 1:
+        raise GrokError("%r must implement at least one interface "
                         "(use grok.implements to specify)."
                         % class_, class_)
+    elif len(list(interface.implementedBy(class_))) > 1:
+        raise GrokError("%r is implementing more than one interface "
+                        "(use grok.provides to specify which one to use)."
+                        % class_, class_)
 
 
 def check_adapts(class_):



More information about the Checkins mailing list