[Checkins] SVN: grok/branches/jw-adapter-decorator/src/grok/ Implement support for @grok.adapter and @grok.implementer

Jan-Wijbrand Kolman jw at infrae.com
Tue Jun 5 05:03:54 EDT 2007


Log message for revision 76351:
  Implement support for @grok.adapter and @grok.implementer 
  decorators for registering a function as an adapter factory.

Changed:
  U   grok/branches/jw-adapter-decorator/src/grok/__init__.py
  U   grok/branches/jw-adapter-decorator/src/grok/_grok.py
  U   grok/branches/jw-adapter-decorator/src/grok/meta.py
  A   grok/branches/jw-adapter-decorator/src/grok/tests/adapter/adapterdecorator.py

-=-
Modified: grok/branches/jw-adapter-decorator/src/grok/__init__.py
===================================================================
--- grok/branches/jw-adapter-decorator/src/grok/__init__.py	2007-06-05 08:50:10 UTC (rev 76350)
+++ grok/branches/jw-adapter-decorator/src/grok/__init__.py	2007-06-05 09:03:54 UTC (rev 76351)
@@ -40,6 +40,7 @@
                             define_permission, require, site)
 from grok._grok import do_grok as grok  # Avoid name clash within _grok
 from grok._grok import SubscribeDecorator as subscribe
+from grok._grok import adapter, implementer
 from grok.error import GrokError, GrokImportError
 from grok.formlib import action, AutoFields, Fields
 from grok.util import url

Modified: grok/branches/jw-adapter-decorator/src/grok/_grok.py
===================================================================
--- grok/branches/jw-adapter-decorator/src/grok/_grok.py	2007-06-05 08:50:10 UTC (rev 76350)
+++ grok/branches/jw-adapter-decorator/src/grok/_grok.py	2007-06-05 09:03:54 UTC (rev 76351)
@@ -15,6 +15,7 @@
 """
 import os
 import sys
+import types
 
 from zope import component
 from zope import interface
@@ -105,3 +106,42 @@
         if subscribers is None:
             frame.f_locals['__grok_subscribers__'] = subscribers = []
         subscribers.append((function, self.subscribed))
+
+def implementer(interface):
+    frame = sys._getframe(1)
+    if not frame_is_module(frame):
+        raise GrokImportError(
+            "@grok.implementer can only be used on module level.")
+
+    def decorated(function):
+        setattr(function, '__grok_implementer__', interface)
+        return function
+
+    return decorated
+
+def adapter(interface_or_function, *additional_interfaces):
+    frame = sys._getframe(1)
+    if not frame_is_module(frame):
+        raise GrokImportError(
+            "@grok.adapter can only be used on module level.")
+
+    def decorated(function):
+        implementer = getattr(function, '__grok_implementer__', None)
+        if implementer is None:
+            raise GrokImportError(
+                "@grok.implementer should be used as inner decorator.")
+
+        implementers = frame.f_locals.get('__grok_implementers__', None)
+        if implementers is None:
+            frame.f_locals['__grok_implementers__'] = implementers = []
+        implementers.append((function, implementer, interfaces))
+
+    if isinstance(interface_or_function, (types.FunctionType,)):
+        # The adapter decorator is without argument, which means the
+        # function to-be-decorated is passed a first argument.
+        function = interface_or_function
+        interfaces = None # we'll try to find a context during grok-time
+        return decorated(function)
+    else:
+        interfaces = (interface_or_function,)+additional_interfaces
+        return decorated

Modified: grok/branches/jw-adapter-decorator/src/grok/meta.py
===================================================================
--- grok/branches/jw-adapter-decorator/src/grok/meta.py	2007-06-05 08:50:10 UTC (rev 76350)
+++ grok/branches/jw-adapter-decorator/src/grok/meta.py	2007-06-05 09:03:54 UTC (rev 76351)
@@ -90,7 +90,7 @@
         methods = util.methods_from_class(factory)
 
         default_permission = util.get_default_permission(factory)
-        
+
         for method in methods:
             # Make sure that the class inherits MethodPublisher, so that the
             # views have a location
@@ -109,7 +109,7 @@
             permission = getattr(method, '__grok_require__',
                                  default_permission)
             util.make_checker(factory, method_view, permission)
-    
+
 class ViewGrokker(grok.ClassGrokker):
     component_class = grok.View
 
@@ -175,7 +175,7 @@
         # protect view, public by default
         default_permission = util.get_default_permission(factory)
         util.make_checker(factory, factory, default_permission)
-    
+
         # safety belt: make sure that the programmer didn't use
         # @grok.require on any of the view's methods.
         methods = util.methods_from_class(factory)
@@ -195,7 +195,7 @@
         methods = util.methods_from_class(factory)
 
         default_permission = util.get_default_permission(factory)
-        
+
         for method in methods:
             # Create a new class with a __view_name__ attribute so the
             # JSON class knows what method to call.
@@ -258,7 +258,19 @@
             for iface in subscribed:
                 zope.component.interface.provideInterface('', iface)
 
+class AdapterDecoratorGrokker(grok.ModuleGrokker):
 
+    def register(self, context, module_info, templates):
+        implementers = module_info.getAnnotation('grok.implementers', [])
+        for function, implementer, interfaces in implementers:
+            if interfaces is None:
+                # There's no explicit interfaces defined, so we assume the
+                # module context to be the thing adapted.
+                util.check_context(module_info.getModule(), context)
+                interfaces = (context, )
+            component.provideAdapter(
+                function, adapts=interfaces, provides=implementer)
+
 class StaticResourcesGrokker(grok.ModuleGrokker):
 
     def register(self, context, module_info, templates):
@@ -429,10 +441,10 @@
 
     if setup is not None:
         setup(utility)
-        
+
     site_manager.registerUtility(utility, provided=provides,
                                  name=name)
-    
+
 class DefinePermissionGrokker(grok.ModuleGrokker):
 
     priority = 1500
@@ -452,7 +464,7 @@
 
 class AnnotationGrokker(grok.ClassGrokker):
     component_class = grok.Annotation
- 
+
     def register(self, context, name, factory, module_info, templates):
         adapter_context = util.determine_class_context(factory, context)
         provides = util.class_annotation(factory, 'grok.provides', None)
@@ -518,14 +530,14 @@
                                    context, module_info),
             adapts=(site,
                     grok.IObjectAddedEvent))
-        
+
 class IndexesSetupSubscriber(object):
     def __init__(self, catalog_name, indexes, context, module_info):
         self.catalog_name = catalog_name
         self.indexes = indexes
         self.context = context
         self.module_info = module_info
-        
+
     def __call__(self, site, event):
         # make sure we have an intids
         self._createIntIds(site)
@@ -555,7 +567,7 @@
         catalog = Catalog()
         setupUtility(site, catalog, ICatalog, name=self.catalog_name)
         return catalog
-    
+
     def _createIntIds(self, site):
         """Create intids if needed, and return it.
         """

Added: grok/branches/jw-adapter-decorator/src/grok/tests/adapter/adapterdecorator.py
===================================================================
--- grok/branches/jw-adapter-decorator/src/grok/tests/adapter/adapterdecorator.py	                        (rev 0)
+++ grok/branches/jw-adapter-decorator/src/grok/tests/adapter/adapterdecorator.py	2007-06-05 09:03:54 UTC (rev 76351)
@@ -0,0 +1,91 @@
+"""
+ at grok.adapter can only be used on module level::
+
+  >>> function_context()
+  Traceback (most recent call last):
+    ...
+  GrokImportError: @grok.adapter can only be used on module level.
+
+  >>> class_context()
+  Traceback (most recent call last):
+    ...
+  GrokImportError: @grok.adapter can only be used on module level.
+
+  >>> @grok.adapter(Cave)
+  ... def func():
+  ...     pass
+  Traceback (most recent call last):
+    ...
+  GrokImportError: @grok.implementer should be used as inner decorator.
+
+  >>> grok.grok(__name__)
+  >>> cave = Cave()
+  >>> home = IHome(cave)
+  >>> IHome.providedBy(home)
+  True
+  >>> isinstance(home, Home)
+  True
+  >>> anotherhome = IAnotherHome(cave)
+  >>> IHome.providedBy(anotherhome)
+  True
+  >>> isinstance(anotherhome, Home)
+  True
+  >>> morehome = IMoreHome(cave)
+  >>> IHome.providedBy(morehome)
+  True
+  >>> isinstance(morehome, Home)
+  True
+"""
+
+import grok
+from zope import interface
+
+class IDummy(interface.Interface):
+    pass
+
+def function_context():
+    @grok.adapter(IDummy)
+    @grok.implementer(IDummy)
+    def subscriber():
+        pass
+
+def class_context():
+    class Wrapper:
+        @grok.adapter(IDummy)
+        @grok.implementer(IDummy)
+        def subscriber(self):
+            pass
+
+class ICave(interface.Interface):
+    pass
+
+class IHome(interface.Interface):
+    pass
+
+class IAnotherHome(interface.Interface):
+    pass
+
+class IMoreHome(interface.Interface):
+    pass
+
+class Cave(grok.Model):
+    grok.implements(ICave)
+    pass
+
+class Home(object):
+    grok.implements(IHome)
+
+ at grok.adapter(Cave)
+ at grok.implementer(IHome)
+def home_for_cave(cave):
+    return Home()
+
+ at grok.adapter
+ at grok.implementer(IAnotherHome)
+def another_home_for_cave(cave):
+    return Home()
+
+ at grok.adapter(ICave)
+ at grok.implementer(IMoreHome)
+def more_home_for_cave(cave):
+    return Home()



More information about the Checkins mailing list