[Checkins] SVN: grok/trunk/src/grok/ first stab at grok.local_utility. Needs a lot more tests.

Wolfgang Schnerring wosc at wosc.de
Sat Jan 6 12:54:21 EST 2007


Log message for revision 71747:
  first stab at grok.local_utility. Needs a lot more tests.

Changed:
  U   grok/trunk/src/grok/__init__.py
  U   grok/trunk/src/grok/components.py
  U   grok/trunk/src/grok/directive.py
  U   grok/trunk/src/grok/ftests/test_grok_functional.py
  A   grok/trunk/src/grok/ftests/utility/
  A   grok/trunk/src/grok/ftests/utility/__init__.py
  A   grok/trunk/src/grok/ftests/utility/local.py
  U   grok/trunk/src/grok/grokker.py
  U   grok/trunk/src/grok/interfaces.py
  U   grok/trunk/src/grok/meta.py

-=-
Modified: grok/trunk/src/grok/__init__.py
===================================================================
--- grok/trunk/src/grok/__init__.py	2007-01-06 17:10:41 UTC (rev 71746)
+++ grok/trunk/src/grok/__init__.py	2007-01-06 17:54:20 UTC (rev 71747)
@@ -31,11 +31,11 @@
 
 from grok.components import ClassGrokker, InstanceGrokker, ModuleGrokker
 from grok.components import Model, Adapter, MultiAdapter, View, XMLRPC
-from grok.components import PageTemplate, GlobalUtility, Container, Traverser
-from grok.components import Site
+from grok.components import PageTemplate, Container, Traverser
+from grok.components import Site, GlobalUtility, LocalUtility
 from grok.components import EditForm, DisplayForm, AddForm
 from grok.directive import (context, name, template, templatedir, provides,
-                            global_utility)
+                            global_utility, local_utility)
 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/components.py
===================================================================
--- grok/trunk/src/grok/components.py	2007-01-06 17:10:41 UTC (rev 71746)
+++ grok/trunk/src/grok/components.py	2007-01-06 17:54:20 UTC (rev 71747)
@@ -115,6 +115,10 @@
     pass
 
 
+class LocalUtility(Model):
+    pass
+
+
 class MultiAdapter(object):
     pass
 

Modified: grok/trunk/src/grok/directive.py
===================================================================
--- grok/trunk/src/grok/directive.py	2007-01-06 17:10:41 UTC (rev 71746)
+++ grok/trunk/src/grok/directive.py	2007-01-06 17:54:20 UTC (rev 71747)
@@ -181,6 +181,26 @@
         self.provides = provides
         self.name = name
 
+class LocalUtilityDirective(MultipleTimesDirective):
+    def check_arguments(self, factory, provides=None, name=u'',
+                        setup=None, hide=True, name_in_container=None):
+        if provides is not None and not IInterface.providedBy(provides):
+            raise GrokImportError("You can only pass an interface to the "
+                                  "provides argument of %s." % self.name)
+
+    def value_factory(self, *args, **kw):
+        return LocalUtilityInfo(*args, **kw)
+
+class LocalUtilityInfo(object):
+    def __init__(self, factory, provides=None, name=u'',
+                 setup=None, hide=True, name_in_container=None):
+        self.factory = factory
+        self.provides = provides
+        self.name = name
+        self.setup = setup
+        self.hide = hide
+        self.name_in_container = name_in_container
+
 # Define grok directives
 name = TextDirective('grok.name', ClassDirectiveContext())
 template = TextDirective('grok.template', ClassDirectiveContext())
@@ -190,3 +210,5 @@
 provides = InterfaceDirective('grok.provides', ClassDirectiveContext())
 global_utility = GlobalUtilityDirective('grok.global_utility',
                                         ModuleDirectiveContext())
+local_utility = LocalUtilityDirective('grok.local_utility',
+                                      ClassDirectiveContext())

Modified: grok/trunk/src/grok/ftests/test_grok_functional.py
===================================================================
--- grok/trunk/src/grok/ftests/test_grok_functional.py	2007-01-06 17:10:41 UTC (rev 71746)
+++ grok/trunk/src/grok/ftests/test_grok_functional.py	2007-01-06 17:54:20 UTC (rev 71747)
@@ -57,7 +57,7 @@
 def test_suite():
     suite = unittest.TestSuite()
     for name in ['view', 'static', 'xmlrpc', 'traversal', 'form', 'url',
-                 'security']:
+                 'security', 'utility']:
         suite.addTest(suiteFromPackage(name))
     return suite
 

Added: grok/trunk/src/grok/ftests/utility/__init__.py
===================================================================
--- grok/trunk/src/grok/ftests/utility/__init__.py	2007-01-06 17:10:41 UTC (rev 71746)
+++ grok/trunk/src/grok/ftests/utility/__init__.py	2007-01-06 17:54:20 UTC (rev 71747)
@@ -0,0 +1 @@
+# this is a package

Added: grok/trunk/src/grok/ftests/utility/local.py
===================================================================
--- grok/trunk/src/grok/ftests/utility/local.py	2007-01-06 17:10:41 UTC (rev 71746)
+++ grok/trunk/src/grok/ftests/utility/local.py	2007-01-06 17:54:20 UTC (rev 71747)
@@ -0,0 +1,40 @@
+"""
+Local Utilities can be registered on subclasses of grok.Site using
+grok.local_utility:
+
+  >>> import grok
+  >>> from zope import component
+  >>> from grok.ftests.utility.local import Cave, Fireplace, IFireplace
+
+  >>> grok.grok('grok.ftests.utility.local')
+
+  >>> cave = Cave()
+  >>> getRootFolder()["cave"] = cave
+
+  >>> from zope.app.component.hooks import getSite, setSite
+  >>> setSite(cave)
+  >>> fireplace = component.getUtility(IFireplace)
+  >>> IFireplace.providedBy(fireplace)
+  True
+  >>> isinstance(fireplace, Fireplace)
+  True
+
+Since it is a local utility, it is not available outside its site:
+
+  >>> setSite(None)
+  >>> component.getUtility(IFireplace)
+  Traceback (most recent call last):
+    ...
+  ComponentLookupError: (<InterfaceClass grok.ftests.utility.local.IFireplace>, '')
+"""
+import grok
+from zope import interface
+
+class IFireplace(interface.Interface):
+    pass
+
+class Fireplace(grok.LocalUtility):
+    grok.implements(IFireplace)
+
+class Cave(grok.Model, grok.Site):
+    grok.local_utility(Fireplace, provides=IFireplace)

Modified: grok/trunk/src/grok/grokker.py
===================================================================
--- grok/trunk/src/grok/grokker.py	2007-01-06 17:10:41 UTC (rev 71746)
+++ grok/trunk/src/grok/grokker.py	2007-01-06 17:54:20 UTC (rev 71747)
@@ -55,6 +55,7 @@
         # this should be made extensible
         possible_contexts = [obj for (name, obj) in
                              (scanned_results.get(grok.Model, []) +
+                              scanned_results.get(grok.LocalUtility, []) +
                               scanned_results.get(grok.Container, []))]
         context = util.determine_module_context(module_info, possible_contexts)
         

Modified: grok/trunk/src/grok/interfaces.py
===================================================================
--- grok/trunk/src/grok/interfaces.py	2007-01-06 17:10:41 UTC (rev 71746)
+++ grok/trunk/src/grok/interfaces.py	2007-01-06 17:54:20 UTC (rev 71747)
@@ -29,6 +29,7 @@
     Adapter = interface.Attribute("Base class for adapters.")
     MultiAdapter = interface.Attribute("Base class for multi-adapters.")
     GlobalUtility = interface.Attribute("Base class for global utilities.")
+    LocalUtility = interface.Attribute("Base class for local utilities.")
     View = interface.Attribute("Base class for browser views.")
     XMLRPC = interface.Attribute("Base class for XML-RPC methods.")
     Traverser = interface.Attribute("Base class for custom traversers.")
@@ -83,6 +84,28 @@
         """Explicitly specify with which interface a component will be looked up.
         """
 
+    def global_utility(factory, provides=None, name=u''):
+        """Register a global utility.
+
+        factory - the factory that creates the global utility
+        provides - the interface the utility should be looked up with
+        name - the name of the utility
+        """
+
+    def local_utility(factory, provides=None, name=u'',
+                      setup=None, hidden=True, name_in_container=None):
+        """Register a local utility.
+
+        factory - the factory that creates the local utility
+        provides - the interface the utility should be looked up with
+        name - the name of the utility
+        setup - a callable that receives the utility as its single argument,
+                it is called after the utility has been created and stored
+        hidden - if True, the utility will be stored below ++etc++site
+                 if False, the utility will be stored directly in the site
+        name_in_container - the name to use for storing the utility
+        """
+
 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 17:10:41 UTC (rev 71746)
+++ grok/trunk/src/grok/meta.py	2007-01-06 17:54:20 UTC (rev 71747)
@@ -8,6 +8,7 @@
                                                IBrowserPublisher)
 from zope.app.publisher.xmlrpc import MethodPublisher
 from zope.publisher.interfaces.xmlrpc import IXMLRPCRequest
+from zope.app.container.interfaces import INameChooser
 
 import grok
 from grok import util, components, formlib
@@ -23,6 +24,9 @@
 class ContainerGrokker(ModelGrokker):
     component_class = grok.Container
     
+class LocalUtilityGrokker(ModelGrokker):
+    component_class = grok.LocalUtility
+    
 class AdapterGrokker(grok.ClassGrokker):
     component_class = grok.Adapter
 
@@ -232,4 +236,45 @@
             component.provideUtility(info.factory(),
                                      provides=info.provides,
                                      name=info.name)
+class SiteGrokker(grok.ClassGrokker):
+    component_class = grok.Site
+    priority = 500
+    continue_scanning = True
 
+    def register(self, context, name, factory, module_info, templates):
+        infos = util.class_annotation(factory, 'grok.local_utility', None)
+        if infos is None:
+            return
+        subscriber = LocalUtilityRegistrationSubscriber(infos)
+        component.provideHandler(subscriber,
+                                 adapts=(factory, grok.IObjectAddedEvent))
+
+class LocalUtilityRegistrationSubscriber(object):
+    def __init__(self, infos):
+        self.infos = infos
+
+    def __call__(self, site, event):
+        for info in self.infos:
+            utility = info.factory()
+            site_manager = site.getSiteManager()
+            
+            # store utility
+            if info.hide:
+                container = site_manager['default']
+            else:
+                container = site
+                
+            name_in_container = info.name_in_container 
+            if name_in_container is None:
+                name_in_container = INameChooser(container).chooseName(
+                    info.factory.__class__.__name__,
+                    utility)
+            container[name_in_container] = utility
+
+            # execute setup callback
+            if info.setup is not None:
+                info.setup(utility)
+
+            # register utility
+            site_manager.registerUtility(utility, provided=info.provides,
+                                         name=info.name)



More information about the Checkins mailing list