[Checkins] SVN: grokcore.component/branches/sylvain-subscribers/src/grokcore/component/ Add more tests.

Sylvain Viollon sylvain at infrae.com
Wed Jan 26 08:31:06 EST 2011


Log message for revision 119944:
  Add more tests.
  Support subscriber registration using decorators.
  
  

Changed:
  U   grokcore.component/branches/sylvain-subscribers/src/grokcore/component/decorators.py
  U   grokcore.component/branches/sylvain-subscribers/src/grokcore/component/meta.py
  U   grokcore.component/branches/sylvain-subscribers/src/grokcore/component/tests/event/subscriber.py
  A   grokcore.component/branches/sylvain-subscribers/src/grokcore/component/tests/subscriber/decorator.py
  U   grokcore.component/branches/sylvain-subscribers/src/grokcore/component/tests/subscriber/ordered_multisubscribers.py
  U   grokcore.component/branches/sylvain-subscribers/src/grokcore/component/tests/subscriber/subscribers.py
  U   grokcore.component/branches/sylvain-subscribers/src/grokcore/component/util.py

-=-
Modified: grokcore.component/branches/sylvain-subscribers/src/grokcore/component/decorators.py
===================================================================
--- grokcore.component/branches/sylvain-subscribers/src/grokcore/component/decorators.py	2011-01-26 11:31:48 UTC (rev 119943)
+++ grokcore.component/branches/sylvain-subscribers/src/grokcore/component/decorators.py	2011-01-26 13:31:06 UTC (rev 119944)
@@ -37,14 +37,17 @@
             raise GrokImportError("@grok.subscribe requires at least one "
                                   "argument.")
 
+        # Add the function and subscribed interfaces to the
+        # grok.subscribers module annotation.
         subscribers = frame.f_locals.get('__grok_subscribers__', None)
         if subscribers is None:
             frame.f_locals['__grok_subscribers__'] = subscribers = []
         subscribers.append((function, self.subscribed))
 
-        # Also add __grok_adapts__ attribute to the function so that
-        # you can manually register the subscriber with, say,
-        # provideHandler.
+        # Also store the subscribed interfaces on the
+        # attribute__component_adapts__ for provideHandler to register
+        # the subscriber (in case you don't grok your package and
+        # register it manually)
         return zope.component.adapter(*self.subscribed)(function)
 
 class adapter(zope.component.adapter):
@@ -59,18 +62,18 @@
         if type(interfaces[0]) is types.FunctionType:
             raise GrokImportError(
                 "@grok.adapter requires at least one argument.")
-        
+
         self.name = u""
-        
+
         if kw:
             if 'name' in kw:
                 self.name = kw.pop('name')
             if kw:
                 raise GrokImportError(
                     "@grok.adapter got unexpected keyword arguments: %s" % ','.join(kw.keys()))
-        
+
         zope.component.adapter.__init__(self, *interfaces)
-    
+
     def __call__(self, ob):
         ob = zope.component.adapter.__call__(self, ob)
         if self.name:
@@ -87,6 +90,7 @@
         if adapters is None:
             frame.f_locals['__grok_adapters__'] = adapters = []
         adapters.append(ob)
+
         return zope.interface.implementer.__call__(self, ob)
 
 class provider:

Modified: grokcore.component/branches/sylvain-subscribers/src/grokcore/component/meta.py
===================================================================
--- grokcore.component/branches/sylvain-subscribers/src/grokcore/component/meta.py	2011-01-26 11:31:48 UTC (rev 119943)
+++ grokcore.component/branches/sylvain-subscribers/src/grokcore/component/meta.py	2011-01-26 13:31:06 UTC (rev 119944)
@@ -13,12 +13,15 @@
 ##############################################################################
 """Grokkers for the various components."""
 
+import operator
+
 import martian
 import martian.util
 import grokcore.component
 import zope.component.interface
 from zope import component, interface
 from martian.error import GrokError
+from zope.interface import implementedBy
 
 def _provides(component, module=None, **data):
     martian.util.check_implements_one(component)
@@ -125,11 +128,18 @@
         return True
 
 
-class AdapterDecoratorGrokker(martian.GlobalGrokker):
+class ImplementerDecoratorGrokker(martian.GlobalGrokker):
 
     def grok(self, name, module, module_info, config, **kw):
         adapters = module_info.getAnnotation('grok.adapters', [])
+        subscribers = set(map(operator.itemgetter(0),
+                              module_info.getAnnotation('grok.subscribers', [])))
+
         for function in adapters:
+            if function in subscribers:
+                # We don't register function that uses the
+                # grok.subscribe directive with grok.implementer.
+                continue
             interfaces = getattr(function, '__component_adapts__', None)
             if interfaces is None:
                 context = grokcore.component.context.bind().get(module)
@@ -205,16 +215,29 @@
         subscribers = module_info.getAnnotation('grok.subscribers', [])
 
         for factory, subscribed in subscribers:
-            config.action(
-                discriminator=None,
-                callable=component.provideHandler,
-                args=(factory, subscribed),
-                )
+            provides = None
+            implemented = list(implementedBy(factory))
+            if len(implemented) == 1:
+                provides = implemented[0]
 
+            # provideHandler is the same as
+            # provideSubscriptionAdapter, where provides=None.  You
+            # can't use provideSubscriptionAdapter with provides=None
+            # since None is used as a marker value.
+            if provides is None:
+                config.action(
+                    discriminator=None,
+                    callable=component.provideHandler,
+                    args=(factory, subscribed))
+            else:
+                config.action(
+                    discriminator=None,
+                    callable=component.provideSubscriptionAdapter,
+                    args=(factory, subscribed, provides))
+
             for iface in subscribed:
                 config.action(
                     discriminator=None,
                     callable=zope.component.interface.provideInterface,
-                    args=('', iface)
-                    )
+                    args=('', iface))
         return True

Modified: grokcore.component/branches/sylvain-subscribers/src/grokcore/component/tests/event/subscriber.py
===================================================================
--- grokcore.component/branches/sylvain-subscribers/src/grokcore/component/tests/event/subscriber.py	2011-01-26 11:31:48 UTC (rev 119943)
+++ grokcore.component/branches/sylvain-subscribers/src/grokcore/component/tests/event/subscriber.py	2011-01-26 13:31:06 UTC (rev 119944)
@@ -8,9 +8,9 @@
   ['Manfred']
   >>> mammoths2
   ['Manfred']
-  
-The decorated event handling function can also be called directly:  
-  
+
+The decorated event handling function can also be called directly:
+
   >>> mammothAdded(Mammoth('Max'),None)
   >>> mammoths
   ['Manfred', 'Max']

Added: grokcore.component/branches/sylvain-subscribers/src/grokcore/component/tests/subscriber/decorator.py
===================================================================
--- grokcore.component/branches/sylvain-subscribers/src/grokcore/component/tests/subscriber/decorator.py	                        (rev 0)
+++ grokcore.component/branches/sylvain-subscribers/src/grokcore/component/tests/subscriber/decorator.py	2011-01-26 13:31:06 UTC (rev 119944)
@@ -0,0 +1,39 @@
+"""
+  >>> grok.testing.grok(__name__)
+
+  >>> cave = Cave('sweet home')
+
+  >>> subscribers = grok.querySubscribers((cave,), IActivity)
+  >>> subscribers
+  [<grokcore.component.tests.subscriber.decorator.DebuggingGrokcore object at ...>]
+
+  Subscribers are not registered as adapters:
+
+  >>> component.queryAdapter(cave, IActivity)
+
+"""
+
+
+import grokcore.component as grok
+from zope import interface, component
+
+
+class Cave(grok.Context):
+
+    def __init__(self, name):
+        self.name = name
+
+class IActivity(interface.Interface):
+    pass
+
+
+class DebuggingGrokcore(object):
+
+    def __init__(self, where):
+        self.where = where
+
+
+ at grok.subscribe(Cave)
+ at grok.implementer(IActivity)
+def debugging(content):
+    return DebuggingGrokcore(content)


Property changes on: grokcore.component/branches/sylvain-subscribers/src/grokcore/component/tests/subscriber/decorator.py
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Revision

Modified: grokcore.component/branches/sylvain-subscribers/src/grokcore/component/tests/subscriber/ordered_multisubscribers.py
===================================================================
--- grokcore.component/branches/sylvain-subscribers/src/grokcore/component/tests/subscriber/ordered_multisubscribers.py	2011-01-26 11:31:48 UTC (rev 119943)
+++ grokcore.component/branches/sylvain-subscribers/src/grokcore/component/tests/subscriber/ordered_multisubscribers.py	2011-01-26 13:31:06 UTC (rev 119944)
@@ -7,17 +7,35 @@
   You can query a subscribers using multiple components and sort them
   using `grok.order` information:
 
-  >>> subscribers = grok.queryOrderedSubscribers((cave, martijn), IActivity)
-  >>> subscribers
+  >>> ordered_subscribers = grok.queryOrderedSubscribers((cave, martijn), IActivity)
+  >>> ordered_subscribers
   [<grokcore.component.tests.subscriber.ordered_multisubscribers.Cooking object at ...>,
    <grokcore.component.tests.subscriber.ordered_multisubscribers.Gardening object at ...>,
    <grokcore.component.tests.subscriber.ordered_multisubscribers.Cleaning object at ...>]
 
-  >>> _ = map(lambda a: a.do(), subscribers)
+  >>> _ = map(lambda a: a.do(), ordered_subscribers)
   Martijn is cooking in Tilburg cave!
   Martijn is growing pumpkins in Tilburg cave!
   Martijn is cleaning the Tilburg cave.
 
+  Or choose not to:
+
+  >>> subscribers = grok.querySubscribers((cave, martijn), IActivity)
+
+  (still need to sort them on class name in order to have a working doctest)
+
+  >>> subscribers = sorted(subscribers, key=lambda s: s.__class__.__name__)
+  >>> subscribers
+  [<grokcore.component.tests.subscriber.ordered_multisubscribers.Cleaning object at ...>,
+   <grokcore.component.tests.subscriber.ordered_multisubscribers.Cooking object at ...>,
+   <grokcore.component.tests.subscriber.ordered_multisubscribers.Gardening object at ...>]
+
+  >>> _ = map(lambda a: a.do(), subscribers)
+  Martijn is cleaning the Tilburg cave.
+  Martijn is cooking in Tilburg cave!
+  Martijn is growing pumpkins in Tilburg cave!
+
+
 """
 
 import grokcore.component as grok

Modified: grokcore.component/branches/sylvain-subscribers/src/grokcore/component/tests/subscriber/subscribers.py
===================================================================
--- grokcore.component/branches/sylvain-subscribers/src/grokcore/component/tests/subscriber/subscribers.py	2011-01-26 11:31:48 UTC (rev 119943)
+++ grokcore.component/branches/sylvain-subscribers/src/grokcore/component/tests/subscriber/subscribers.py	2011-01-26 13:31:06 UTC (rev 119944)
@@ -14,10 +14,14 @@
   Saturday cleaning sweet home!
   Wednesday cleaning sweet home!
 
+  Subscribers are not registered as adapters:
+
+  >>> component.queryAdapter(cave, ICleaner)
+
 """
 
 import grokcore.component as grok
-from zope import interface
+from zope import interface, component
 
 
 class Cave(grok.Context):

Modified: grokcore.component/branches/sylvain-subscribers/src/grokcore/component/util.py
===================================================================
--- grokcore.component/branches/sylvain-subscribers/src/grokcore/component/util.py	2011-01-26 11:31:48 UTC (rev 119943)
+++ grokcore.component/branches/sylvain-subscribers/src/grokcore/component/util.py	2011-01-26 13:31:06 UTC (rev 119944)
@@ -38,6 +38,10 @@
 
 def querySubscribers(components, interface):
     """Query a list of subscribers on `component` which implements
-    `interface`
+    `interface`.
+
+    :parameter components: list of components to look the subscribers for.
+    :parameter interface: interface that the subscribers should provides.
+    :return: a list of subscribers.
     """
     return component.subscribers(components, interface)



More information about the checkins mailing list