[Checkins] SVN: grok/trunk/src/grok/ Implement proper behavior for subclassing of sites that have local utilities.

Martijn Faassen faassen at infrae.com
Sun Jan 7 10:44:34 EST 2007


Log message for revision 71774:
  Implement proper behavior for subclassing of sites that have local utilities.
  

Changed:
  U   grok/trunk/src/grok/directive.py
  A   grok/trunk/src/grok/ftests/utility/subclass.py
  U   grok/trunk/src/grok/meta.py
  U   grok/trunk/src/grok/tests/test_grok.py
  A   grok/trunk/src/grok/tests/util/
  U   grok/trunk/src/grok/util.py

-=-
Modified: grok/trunk/src/grok/directive.py
===================================================================
--- grok/trunk/src/grok/directive.py	2007-01-07 15:42:30 UTC (rev 71773)
+++ grok/trunk/src/grok/directive.py	2007-01-07 15:44:34 UTC (rev 71774)
@@ -199,7 +199,7 @@
 
 class LocalUtilityDirective(MultipleTimesDirective):
     def check_arguments(self, factory, provides=None, name=u'',
-                        setup=None, hide=True, name_in_container=None):
+                        setup=None, hidden=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)
@@ -209,14 +209,14 @@
 
 class LocalUtilityInfo(object):
     def __init__(self, factory, provides=None, name=u'',
-                 setup=None, hide=True, name_in_container=None):
+                 setup=None, hidden=True, name_in_container=None):
         self.factory = factory
         if provides is None:
             provides = util.class_annotation(factory, 'grok.provides', None)
         self.provides = provides
         self.name = name
         self.setup = setup
-        self.hide = hide
+        self.hidden = hidden
         self.name_in_container = name_in_container
 
 class RequireDirective(BaseTextDirective, SingleValue, MultipleTimesDirective):

Copied: grok/trunk/src/grok/ftests/utility/subclass.py (from rev 71771, grok/branches/wosc-utility-subclassing/src/grok/ftests/utility/subclass.py)

Modified: grok/trunk/src/grok/meta.py
===================================================================
--- grok/trunk/src/grok/meta.py	2007-01-07 15:42:30 UTC (rev 71773)
+++ grok/trunk/src/grok/meta.py	2007-01-07 15:44:34 UTC (rev 71774)
@@ -303,7 +303,7 @@
     continue_scanning = True
 
     def register(self, context, name, factory, module_info, templates):
-        infos = util.class_annotation(factory, 'grok.local_utility', None)
+        infos = util.class_annotation_list(factory, 'grok.local_utility', None)
         if infos is None:
             return
 
@@ -329,22 +329,31 @@
 
                 util.check_implements_one_from_list(provides, info.factory)
                 info.provides = provides[0]
-        
-        subscriber = LocalUtilityRegistrationSubscriber(infos)
+
+        # store infos on site class
+        factory.__grok_utilities_to_install__ = infos
+        subscriber = LocalUtilityRegistrationSubscriber()
         component.provideHandler(subscriber,
                                  adapts=(factory, grok.IObjectAddedEvent))
 
 class LocalUtilityRegistrationSubscriber(object):
-    def __init__(self, infos):
-        self.infos = infos
-
+    """A subscriber that fires to set up local utilities.
+    
+    This class is deliberately stateless. This means that there
+    can be no instance variables.
+    """
     def __call__(self, site, event):
-        for info in self.infos:
+        installed = getattr(site, '__grok_utilities_installed__', False)
+        if installed:
+            return
+    
+        for info in util.class_annotation(site.__class__,
+                                          'grok.utilities_to_install', []):
             utility = info.factory()
             site_manager = site.getSiteManager()
             
             # store utility
-            if info.hide:
+            if info.hidden:
                 container = site_manager['default']
             else:
                 container = site
@@ -364,6 +373,10 @@
             site_manager.registerUtility(utility, provided=info.provides,
                                          name=info.name)
 
+        # we are done. If this subscriber gets fired again, we therefore
+        # do not register utilities anymore
+        site.__grok_utilities_installed__ = True
+        
 class DefinePermissionGrokker(grok.ModuleGrokker):
 
     priority = 1500

Modified: grok/trunk/src/grok/tests/test_grok.py
===================================================================
--- grok/trunk/src/grok/tests/test_grok.py	2007-01-07 15:42:30 UTC (rev 71773)
+++ grok/trunk/src/grok/tests/test_grok.py	2007-01-07 15:44:34 UTC (rev 71774)
@@ -34,7 +34,7 @@
     suite = unittest.TestSuite()
     for name in ['adapter', 'error', 'view', 'scan', 'event', 'security',
                  'zcml', 'static', 'utility', 'xmlrpc', 'container',
-                 'traversal', 'form', 'site', 'grokker', 'directive']:
+                 'traversal', 'form', 'site', 'grokker', 'directive', 'util']:
         suite.addTest(suiteFromPackage(name))
     return suite
 

Copied: grok/trunk/src/grok/tests/util (from rev 71771, grok/branches/wosc-utility-subclassing/src/grok/tests/util)

Modified: grok/trunk/src/grok/util.py
===================================================================
--- grok/trunk/src/grok/util.py	2007-01-07 15:42:30 UTC (rev 71773)
+++ grok/trunk/src/grok/util.py	2007-01-07 15:44:34 UTC (rev 71774)
@@ -53,7 +53,24 @@
 def class_annotation(obj, name, default):
     return getattr(obj, '__%s__' % name.replace('.', '_'), default)
 
+def class_annotation_list(obj, name, default):
+    """This will process annotations that are lists correctly in the face of
+    inheritance.
+    """
+    if class_annotation(obj, name, default) is default:
+        return default
 
+    result = []
+    for base in obj.mro():
+        list = class_annotation(base, name, [])
+        if list not in result:
+            result.append(list)
+
+    result_flattened = []
+    for entry in result:
+        result_flattened.extend(entry)
+    return result_flattened
+
 def defined_locally(obj, dotted_name):
     obj_module = getattr(obj, '__grok_module__', None)
     if obj_module is None:



More information about the Checkins mailing list