[Checkins] SVN: grok/branches/wosc-utility-subclassing/src/grok/ work-in-progress about subclassing and local utilities. failing tests, buyer beware

Wolfgang Schnerring wosc at wosc.de
Sun Jan 7 09:33:22 EST 2007


Log message for revision 71768:
  work-in-progress about subclassing and local utilities. failing tests, buyer beware

Changed:
  U   grok/branches/wosc-utility-subclassing/src/grok/directive.py
  A   grok/branches/wosc-utility-subclassing/src/grok/ftests/utility/subclass.py
  U   grok/branches/wosc-utility-subclassing/src/grok/meta.py
  U   grok/branches/wosc-utility-subclassing/src/grok/tests/test_grok.py
  A   grok/branches/wosc-utility-subclassing/src/grok/tests/util/
  A   grok/branches/wosc-utility-subclassing/src/grok/tests/util/__init__.py
  A   grok/branches/wosc-utility-subclassing/src/grok/tests/util/class_annotation.py
  U   grok/branches/wosc-utility-subclassing/src/grok/util.py

-=-
Modified: grok/branches/wosc-utility-subclassing/src/grok/directive.py
===================================================================
--- grok/branches/wosc-utility-subclassing/src/grok/directive.py	2007-01-07 14:31:29 UTC (rev 71767)
+++ grok/branches/wosc-utility-subclassing/src/grok/directive.py	2007-01-07 14:33:21 UTC (rev 71768)
@@ -190,7 +190,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)
@@ -200,14 +200,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
 
 # Define grok directives

Added: grok/branches/wosc-utility-subclassing/src/grok/ftests/utility/subclass.py
===================================================================
--- grok/branches/wosc-utility-subclassing/src/grok/ftests/utility/subclass.py	2007-01-07 14:31:29 UTC (rev 71767)
+++ grok/branches/wosc-utility-subclassing/src/grok/ftests/utility/subclass.py	2007-01-07 14:33:21 UTC (rev 71768)
@@ -0,0 +1,73 @@
+"""
+Subclassed sites inherit all local utilities of their base classes:
+
+  >>> import grok
+  >>> from zope import component
+  >>> from grok.ftests.utility.subclass import *
+
+  >>> grok.grok('grok.ftests.utility.subclass')
+
+  >>> cave = BigCave()
+  >>> 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
+
+Additional utilities can be registered in the subclass:
+  
+  >>> hollow = HollowCave()
+  >>> getRootFolder()["hollow"] = hollow
+
+  >>> setSite(hollow)
+  >>> fireplace = component.getUtility(IFireplace)
+  >>> IFireplace.providedBy(fireplace)
+  True
+  >>> isinstance(fireplace, Fireplace)
+  True
+
+  >>> painting = component.getUtility(IPainting)
+  >>> IPainting.providedBy(painting)
+  True
+  >>> isinstance(painting, Painting)
+  True
+
+Those do not influence the base class:
+
+  >>> setSite(cave)
+  >>> painting = component.getUtility(IPainting)
+  Traceback (most recent call last):
+    ...
+  ComponentLookupError: (<InterfaceClass grok.ftests.utility.subclass.IPainting>, '')
+"""
+import grok
+from zope import interface
+
+class IFireplace(interface.Interface):
+    pass
+
+class IPainting(interface.Interface):
+    pass
+
+class Fireplace(grok.LocalUtility):
+    grok.implements(IFireplace)
+
+class Painting(grok.LocalUtility):
+    grok.implements(IPainting)
+
+class Cave(grok.Model, grok.Site):
+    # we use name_in_container here to prevent multiple registrations
+    # since storing the utilities multiple times under the same name
+    # would raise a DuplicationError
+    grok.local_utility(Fireplace, name_in_container='fireplace')
+
+class BigCave(Cave):
+    pass
+
+class HollowCave(Cave):
+    grok.local_utility(Painting)

Modified: grok/branches/wosc-utility-subclassing/src/grok/meta.py
===================================================================
--- grok/branches/wosc-utility-subclassing/src/grok/meta.py	2007-01-07 14:31:29 UTC (rev 71767)
+++ grok/branches/wosc-utility-subclassing/src/grok/meta.py	2007-01-07 14:33:21 UTC (rev 71768)
@@ -259,7 +259,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
 
@@ -295,12 +295,18 @@
         self.infos = infos
 
     def __call__(self, site, event):
+        processed = util.class_annotation(site,
+                                          'grok.' + self.__class__.__name__, [])
+        if site.__class__ in processed:
+            import pdb; pdb.set_trace()
+            return
+
         for info in self.infos:
             utility = info.factory()
             site_manager = site.getSiteManager()
             
             # store utility
-            if info.hide:
+            if info.hidden:
                 container = site_manager['default']
             else:
                 container = site
@@ -320,6 +326,10 @@
             site_manager.registerUtility(utility, provided=info.provides,
                                          name=info.name)
 
+        processed = processed[:]
+        processed.append(site.__class__)
+        setattr(site, '__grok_' + self.__class__.__name__ + '__', processed)
+
 class DefinePermissionGrokker(grok.ModuleGrokker):
 
     def register(self, context, module_info, templates):

Modified: grok/branches/wosc-utility-subclassing/src/grok/tests/test_grok.py
===================================================================
--- grok/branches/wosc-utility-subclassing/src/grok/tests/test_grok.py	2007-01-07 14:31:29 UTC (rev 71767)
+++ grok/branches/wosc-utility-subclassing/src/grok/tests/test_grok.py	2007-01-07 14:33:21 UTC (rev 71768)
@@ -34,7 +34,7 @@
     suite = unittest.TestSuite()
     for name in ['adapter', 'error', 'view', 'scan', 'event',
                  'zcml', 'static', 'utility', 'xmlrpc', 'container',
-                 'traversal', 'form', 'site', 'grokker', 'directive']:
+                 'traversal', 'form', 'site', 'grokker', 'directive', 'util']:
         suite.addTest(suiteFromPackage(name))
     return suite
 

Added: grok/branches/wosc-utility-subclassing/src/grok/tests/util/__init__.py
===================================================================
--- grok/branches/wosc-utility-subclassing/src/grok/tests/util/__init__.py	2007-01-07 14:31:29 UTC (rev 71767)
+++ grok/branches/wosc-utility-subclassing/src/grok/tests/util/__init__.py	2007-01-07 14:33:21 UTC (rev 71768)
@@ -0,0 +1 @@
+# this is a package

Added: grok/branches/wosc-utility-subclassing/src/grok/tests/util/class_annotation.py
===================================================================
--- grok/branches/wosc-utility-subclassing/src/grok/tests/util/class_annotation.py	2007-01-07 14:31:29 UTC (rev 71767)
+++ grok/branches/wosc-utility-subclassing/src/grok/tests/util/class_annotation.py	2007-01-07 14:33:21 UTC (rev 71768)
@@ -0,0 +1,28 @@
+"""
+  >>> util.class_annotation_list(B, 'grok.foo', None)
+  [7, 5]
+  >>> util.class_annotation_list(B2, 'grok.foo', None)
+  [5]
+  >>> util.class_annotation_list(C, 'grok.foo', None)
+  [8, 7, 5]
+  >>> util.class_annotation_list(C2, 'grok.foo', None)
+  [9, 5, 7]
+  
+"""
+import grok
+from grok import util
+
+class A(object):
+    __grok_foo__ = [5]
+
+class B(A):
+    __grok_foo__ = [7]
+
+class B2(A):
+    pass
+
+class C(B, B2):
+    __grok_foo__ = [8]
+
+class C2(B2, B):
+    __grok_foo__ = [9]

Modified: grok/branches/wosc-utility-subclassing/src/grok/util.py
===================================================================
--- grok/branches/wosc-utility-subclassing/src/grok/util.py	2007-01-07 14:31:29 UTC (rev 71767)
+++ grok/branches/wosc-utility-subclassing/src/grok/util.py	2007-01-07 14:33:21 UTC (rev 71768)
@@ -52,7 +52,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