[Checkins] SVN: grok/trunk/ - added grok.Container (mix-in approach)

Christian Theune ct at gocept.com
Wed Oct 18 13:24:31 EDT 2006


Log message for revision 70790:
   - added grok.Container (mix-in approach)
   - refactored Model, View & Co to grok.components
   - moved directive definitions to grok.directive
   - moved GrokChecker to grok.security
   - refactored grok method to DRY the detection of our components
  

Changed:
  U   grok/trunk/TODO.txt
  U   grok/trunk/src/grok/__init__.py
  U   grok/trunk/src/grok/_grok.py
  A   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/security.py
  A   grok/trunk/src/grok/tests/container/
  A   grok/trunk/src/grok/tests/container/__init__.py
  A   grok/trunk/src/grok/tests/container/container.py
  U   grok/trunk/src/grok/tests/test_grok.py
  U   grok/trunk/src/grok/util.py

-=-
Modified: grok/trunk/TODO.txt
===================================================================
--- grok/trunk/TODO.txt	2006-10-18 17:19:42 UTC (rev 70789)
+++ grok/trunk/TODO.txt	2006-10-18 17:24:30 UTC (rev 70790)
@@ -17,8 +17,6 @@
 
 - choice fields / sources (theuni)
 
-- containers
-
 - annotations (faassen)
 
 - testing strategy for the tutorial (faassen)

Modified: grok/trunk/src/grok/__init__.py
===================================================================
--- grok/trunk/src/grok/__init__.py	2006-10-18 17:19:42 UTC (rev 70789)
+++ grok/trunk/src/grok/__init__.py	2006-10-18 17:24:30 UTC (rev 70790)
@@ -28,11 +28,10 @@
     IObjectRemovedEvent, ObjectRemovedEvent,
     IContainerModifiedEvent, ContainerModifiedEvent)
 
-from grok._grok import Model, Adapter, MultiAdapter, View, XMLRPC
-from grok._grok import PageTemplate, Utility
-
-from grok._grok import grok, context, name, template, templatedir
-
+from grok.components import Model, Adapter, MultiAdapter, View, XMLRPC
+from grok.components import PageTemplate, Utility, Container
+from grok.directive import context, name, template, templatedir
+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/_grok.py
===================================================================
--- grok/trunk/src/grok/_grok.py	2006-10-18 17:19:42 UTC (rev 70789)
+++ grok/trunk/src/grok/_grok.py	2006-10-18 17:24:30 UTC (rev 70790)
@@ -17,28 +17,21 @@
 import sys
 import inspect
 
-import persistent
 from zope import component
 from zope import interface
-from zope.proxy import removeAllProxies
-from zope.dottedname.resolve import resolve
 import zope.component.interface
 from zope.component.interfaces import IDefaultViewName
 from zope.security.checker import (defineChecker, getCheckerForInstancesOf,
                                    NoProxy)
-from zope.publisher.browser import BrowserPage
 from zope.publisher.interfaces.browser import (IDefaultBrowserLayer,
                                                IBrowserRequest)
-from zope.pagetemplate import pagetemplate
 
-from zope.app.pagetemplate.engine import TrustedAppPT
-from zope.app.publisher.browser import directoryresource
-from zope.app.publisher.browser.pagetemplateresource import \
-    PageTemplateResourceFactory
 from zope.app.publisher.xmlrpc import MethodPublisher
 from zope.publisher.interfaces.xmlrpc import IXMLRPCRequest
 
-from grok import util, scan
+import grok
+
+from grok import util, scan, components, security
 from grok.error import GrokError, GrokImportError
 from grok.directive import (ClassDirectiveContext, ModuleDirectiveContext,
                             ClassOrModuleDirectiveContext,
@@ -48,86 +41,12 @@
 
 AMBIGUOUS_CONTEXT = object()
 
-class Model(persistent.Persistent):
-    pass
 
-class Adapter(object):
-
-    def __init__(self, context):
-        self.context = context
-
-class Utility(object):
-    pass
-
-class MultiAdapter(object):
-    pass
-
-class View(BrowserPage):
-
-    def __init__(self, context, request):
-        self.context = removeAllProxies(context)
-        self.request = removeAllProxies(request)
-
-    def __call__(self):
-        self.before()
-
-        template = getattr(self, 'template', None)
-        if not template:
-            return self.render()
-
-        namespace = template.pt_getContext()
-        namespace['request'] = self.request
-        # Jim would say: WAAAAAAAAAAAAH!
-        namespace['view'] = self
-        namespace['context'] = removeAllProxies(self.context)
-
-        module_info = template.__grok_module_info__
-        directory_resource = component.queryAdapter(self.request,
-                interface.Interface, name=module_info.package_dotted_name)
-        # XXX need to check whether we really want None here
-        namespace['static'] = directory_resource
-        return template.pt_render(namespace)
-
-    def before(self):
-        pass
-
-
-class XMLRPC(object):
-    pass
-
-
-
-class PageTemplate(TrustedAppPT, pagetemplate.PageTemplate):
-    expand = 0
-
-    def __init__(self, template):
-        super(PageTemplate, self).__init__()
-        if util.not_unicode_or_ascii(template):
-            raise ValueError("Invalid page template. Page templates must be "
-                             "unicode or ASCII.")
-        self.write(template)
-
-        # __grok_module__ is needed to make defined_locally() return True for
-        # inline templates
-        # XXX unfortunately using caller_module means that
-        # PageTemplate cannot be subclassed
-        self.__grok_module__ = caller_module()
-
-    def __repr__(self):
-        return '<%s template in %s>' % (self.__grok_name__,
-                                        self.__grok_location__)
-
-    def _annotateGrokInfo(self, module_info, name, location):
-        self.__grok_module_info__ = module_info
-        self.__grok_name__ = name
-        self.__grok_location__ = location
-
-
-def grok(dotted_name):
+def do_grok(dotted_name):
     # register the name 'index' as the default view name
     # TODO this needs to be moved to grok startup time (similar to ZCML-time)
     component.provideAdapter('index',
-                             adapts=(Model, IBrowserRequest),
+                             adapts=(grok.Model, IBrowserRequest),
                              provides=IDefaultViewName)
 
     module_info = scan.module_info_from_dotted_name(dotted_name)
@@ -178,12 +97,12 @@
 
 def scan_module(module_info):
     components = {
-            Model: [],
-            Adapter: [],
-            MultiAdapter: [],
-            Utility: [],
-            View: [],
-            XMLRPC: []
+            grok.Model: [],
+            grok.Adapter: [],
+            grok.MultiAdapter: [],
+            grok.Utility: [],
+            grok.View: [],
+            grok.XMLRPC: []
             }
     templates = TemplateRegistry()
     subscribers = module_info.getAnnotation('grok.subscribers', [])
@@ -195,7 +114,7 @@
         if not defined_locally(obj, module_info.dotted_name):
             continue
 
-        if isinstance(obj, PageTemplate):
+        if isinstance(obj, grok.PageTemplate):
             templates.register(name, obj)
             obj._annotateGrokInfo(module_info, name, module_info.dotted_name)
             continue
@@ -205,9 +124,9 @@
                 found_list.append(obj)
                 break
 
-    return (components[Model], components[Adapter], 
-            components[MultiAdapter], components[Utility],
-            components[View], components[XMLRPC], templates, subscribers)
+    return (components[grok.Model], components[grok.Adapter], 
+            components[grok.MultiAdapter], components[grok.Utility],
+            components[grok.View], components[grok.XMLRPC], templates, subscribers)
 
 def find_filesystem_templates(module_info, templates):
     template_dir_name = module_info.getAnnotation('grok.templatedir', module_info.name)
@@ -230,7 +149,7 @@
             contents = f.read()
             f.close()
 
-            template = PageTemplate(contents)
+            template = grok.PageTemplate(contents)
             template._annotateGrokInfo(module_info, template_name,
                                        template_path)
             #template.__grok_name__ = template_name
@@ -246,64 +165,8 @@
             templates.register(template_name, template)
 
 
-class GrokDirectoryResource(directoryresource.DirectoryResource):
-    # We subclass this, because we want to override the default factories for
-    # the resources so that .pt and .html do not get created as page
-    # templates
-
-    resource_factories = {}
-    for type, factory in (directoryresource.DirectoryResource.
-                          resource_factories.items()):
-        if factory is PageTemplateResourceFactory:
-            continue
-        resource_factories[type] = factory
-
-
-class GrokDirectoryResourceFactory(object):
-    # We need this to allow hooking up our own GrokDirectoryResource
-    # and to set the checker to None (until we have our own checker)
-
-    def __init__(self, path, name):
-        # XXX we're not sure about the checker=None here
-        self.__dir = directoryresource.Directory(path, None, name)
-        self.__name = name
-
-    def __call__(self, request):
-        resource = GrokDirectoryResource(self.__dir, request)
-        resource.__Security_checker__ = GrokChecker()
-        resource.__name__ = self.__name
-        return resource
-
-class GrokChecker(object):
-    # ME GROK ANGRY.
-    # ME GROK NOT KNOW WHY CHECKER.
-
-    # We have no idea why we need a custom checker here. One hint was
-    # that the DirectoryResource already does something manually with
-    # setting up the 'correct' checker for itself and we seem to interfere
-    # with that. However, we couldn't figure out what's going on and this
-    # solves our problem for now. 
-
-    # XXX re-implement this in a sane way.
-
-    def __init__(self):
-        pass
-
-    def check_getattr(self, object, name):
-        pass
-
-    def check_setattr(self, ob, name):
-        pass
-
-    def check(self, ob, operation):
-        pass
-
-    def proxy(self, value):
-        return value
-
-
 def register_static_resources(dotted_name, resource_directory):
-    resource_factory = GrokDirectoryResourceFactory(resource_directory,
+    resource_factory = components.DirectoryResourceFactory(resource_directory,
                                                     dotted_name)
     component.provideAdapter(resource_factory, (IDefaultBrowserLayer,),
                              interface.Interface, name=dotted_name)
@@ -344,8 +207,9 @@
             # Make sure that the class inherits MethodPublisher, so that the views
             # have a location
             method_view = type(view.__name__, (view, MethodPublisher), 
-                               {'__call__':method,
-                                '__Security_checker__':GrokChecker()})
+                               {'__call__': method,
+                                '__Security_checker__': security.GrokChecker()}
+                               )
             component.provideAdapter(
                 method_view, (view_context, IXMLRPCRequest), interface.Interface,
                 name=method.__name__)
@@ -397,7 +261,7 @@
     for name, unassociated in templates.listUnassociatedTemplates():
         check_context(unassociated, context)
 
-        class TemplateView(View):
+        class TemplateView(grok.View):
             template = unassociated
 
         templates.markAssociated(name)
@@ -486,16 +350,7 @@
 def class_annotation(obj, name, default):
     return getattr(obj, '__%s__' % name.replace('.', '_'), default)
 
-def caller_module():
-    return sys._getframe(2).f_globals['__name__']
 
-# directives
-name = TextDirective('grok.name', ClassDirectiveContext())
-template = TextDirective('grok.template', ClassDirectiveContext())
-context = InterfaceOrClassDirective('grok.context',
-                                    ClassOrModuleDirectiveContext())
-templatedir = TextDirective('grok.templatedir', ModuleDirectiveContext())
-
 # decorators
 class SubscribeDecorator:
     def __init__(self, *args):

Added: grok/trunk/src/grok/components.py
===================================================================
--- grok/trunk/src/grok/components.py	2006-10-18 17:19:42 UTC (rev 70789)
+++ grok/trunk/src/grok/components.py	2006-10-18 17:24:30 UTC (rev 70790)
@@ -0,0 +1,140 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok components
+"""
+
+import persistent
+from zope import component
+from zope import interface
+from zope.proxy import removeAllProxies
+from zope.publisher.browser import BrowserPage
+from zope.pagetemplate import pagetemplate
+
+from zope.app.pagetemplate.engine import TrustedAppPT
+from zope.app.publisher.browser import directoryresource
+from zope.app.publisher.browser.pagetemplateresource import \
+    PageTemplateResourceFactory
+from zope.app.container.btree import BTreeContainer
+
+from grok import util, security
+
+class Model(persistent.Persistent):
+    pass
+
+
+class Container(BTreeContainer):
+    pass
+
+
+class Adapter(object):
+
+    def __init__(self, context):
+        self.context = context
+
+
+class Utility(object):
+    pass
+
+class MultiAdapter(object):
+    pass
+
+class View(BrowserPage):
+
+    def __init__(self, context, request):
+        self.context = removeAllProxies(context)
+        self.request = removeAllProxies(request)
+
+    def __call__(self):
+        self.before()
+
+        template = getattr(self, 'template', None)
+        if not template:
+            return self.render()
+
+        namespace = template.pt_getContext()
+        namespace['request'] = self.request
+        # Jim would say: WAAAAAAAAAAAAH!
+        namespace['view'] = self
+        namespace['context'] = removeAllProxies(self.context)
+
+        module_info = template.__grok_module_info__
+        directory_resource = component.queryAdapter(self.request,
+                interface.Interface, name=module_info.package_dotted_name)
+        # XXX need to check whether we really want None here
+        namespace['static'] = directory_resource
+        return template.pt_render(namespace)
+
+    def before(self):
+        pass
+
+
+class XMLRPC(object):
+    pass
+
+
+
+class PageTemplate(TrustedAppPT, pagetemplate.PageTemplate):
+    expand = 0
+
+    def __init__(self, template):
+        super(PageTemplate, self).__init__()
+        if util.not_unicode_or_ascii(template):
+            raise ValueError("Invalid page template. Page templates must be "
+                             "unicode or ASCII.")
+        self.write(template)
+
+        # __grok_module__ is needed to make defined_locally() return True for
+        # inline templates
+        # XXX unfortunately using caller_module means that
+        # PageTemplate cannot be subclassed
+        self.__grok_module__ = util.caller_module()
+
+    def __repr__(self):
+        return '<%s template in %s>' % (self.__grok_name__,
+                                        self.__grok_location__)
+
+    def _annotateGrokInfo(self, module_info, name, location):
+        self.__grok_module_info__ = module_info
+        self.__grok_name__ = name
+        self.__grok_location__ = location
+
+
+class DirectoryResource(directoryresource.DirectoryResource):
+    # We subclass this, because we want to override the default factories for
+    # the resources so that .pt and .html do not get created as page
+    # templates
+
+    resource_factories = {}
+    for type, factory in (directoryresource.DirectoryResource.
+                          resource_factories.items()):
+        if factory is PageTemplateResourceFactory:
+            continue
+        resource_factories[type] = factory
+
+
+class DirectoryResourceFactory(object):
+    # We need this to allow hooking up our own GrokDirectoryResource
+    # and to set the checker to None (until we have our own checker)
+
+    def __init__(self, path, name):
+        # XXX we're not sure about the checker=None here
+        self.__dir = directoryresource.Directory(path, None, name)
+        self.__name = name
+
+    def __call__(self, request):
+        resource = DirectoryResource(self.__dir, request)
+        resource.__Security_checker__ = security.GrokChecker()
+        resource.__name__ = self.__name
+        return resource
+


Property changes on: grok/trunk/src/grok/components.py
___________________________________________________________________
Name: svn:keywords
   + Id Rev Date
Name: svn:eol-style
   + native

Modified: grok/trunk/src/grok/directive.py
===================================================================
--- grok/trunk/src/grok/directive.py	2006-10-18 17:19:42 UTC (rev 70789)
+++ grok/trunk/src/grok/directive.py	2006-10-18 17:24:30 UTC (rev 70790)
@@ -111,3 +111,11 @@
         if not (IInterface.providedBy(value) or util.isclass(value)):
             raise GrokImportError("You can only pass classes or interfaces to "
                                   "%s." % self.name)
+
+
+# Define grok directives
+name = TextDirective('grok.name', ClassDirectiveContext())
+template = TextDirective('grok.template', ClassDirectiveContext())
+context = InterfaceOrClassDirective('grok.context',
+                                    ClassOrModuleDirectiveContext())
+templatedir = TextDirective('grok.templatedir', ModuleDirectiveContext())

Modified: grok/trunk/src/grok/ftests/test_grok_functional.py
===================================================================
--- grok/trunk/src/grok/ftests/test_grok_functional.py	2006-10-18 17:19:42 UTC (rev 70789)
+++ grok/trunk/src/grok/ftests/test_grok_functional.py	2006-10-18 17:24:30 UTC (rev 70790)
@@ -1,6 +1,6 @@
 import unittest
 from pkg_resources import resource_listdir
-from zope.testing import doctest, cleanup
+from zope.testing import doctest
 from zope.app.testing.functional import HTTPCaller, getRootFolder, FunctionalTestSetup, sync, Functional
 
 # XXX bastardized from zope.app.testing.functional.FunctionalDocFileSuite :-(

Added: grok/trunk/src/grok/security.py
===================================================================
--- grok/trunk/src/grok/security.py	2006-10-18 17:19:42 UTC (rev 70789)
+++ grok/trunk/src/grok/security.py	2006-10-18 17:24:30 UTC (rev 70790)
@@ -0,0 +1,45 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok security-related stuff
+"""
+
+class GrokChecker(object):
+    # ME GROK ANGRY.
+    # ME GROK NOT KNOW WHY CHECKER.
+
+    # We have no idea why we need a custom checker here. One hint was
+    # that the DirectoryResource already does something manually with
+    # setting up the 'correct' checker for itself and we seem to interfere
+    # with that. However, we couldn't figure out what's going on and this
+    # solves our problem for now. 
+
+    # XXX re-implement this in a sane way.
+
+    def __init__(self):
+        pass
+
+    def check_getattr(self, object, name):
+        pass
+
+    def check_setattr(self, ob, name):
+        pass
+
+    def check(self, ob, operation):
+        pass
+
+    def proxy(self, value):
+        return value
+
+
+


Property changes on: grok/trunk/src/grok/security.py
___________________________________________________________________
Name: svn:keywords
   + Id Rev Date
Name: svn:eol-style
   + native

Added: grok/trunk/src/grok/tests/container/__init__.py
===================================================================
--- grok/trunk/src/grok/tests/container/__init__.py	2006-10-18 17:19:42 UTC (rev 70789)
+++ grok/trunk/src/grok/tests/container/__init__.py	2006-10-18 17:24:30 UTC (rev 70790)
@@ -0,0 +1 @@
+# this is a package


Property changes on: grok/trunk/src/grok/tests/container/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id Rev Date
Name: svn:eol-style
   + native

Added: grok/trunk/src/grok/tests/container/container.py
===================================================================
--- grok/trunk/src/grok/tests/container/container.py	2006-10-18 17:19:42 UTC (rev 70789)
+++ grok/trunk/src/grok/tests/container/container.py	2006-10-18 17:24:30 UTC (rev 70790)
@@ -0,0 +1,21 @@
+"""
+
+The grok.Container is just a convenient subclass of the BTreeContainer that lives in the Zope 3 core:
+
+    >>> grok.grok(__name__)
+
+    >>> from zope.app.container.interfaces import IContainer
+    >>> bag = BoneBag()
+    >>> IContainer.providedBy(bag)
+    True
+
+    >>> from zope.app.container.btree import BTreeContainer
+    >>> isinstance(bag, BTreeContainer)
+    True
+
+"""
+
+import grok
+
+class BoneBag(grok.Model, grok.Container):
+    pass


Property changes on: grok/trunk/src/grok/tests/container/container.py
___________________________________________________________________
Name: svn:keywords
   + Id Rev Date
Name: svn:eol-style
   + native

Modified: grok/trunk/src/grok/tests/test_grok.py
===================================================================
--- grok/trunk/src/grok/tests/test_grok.py	2006-10-18 17:19:42 UTC (rev 70789)
+++ grok/trunk/src/grok/tests/test_grok.py	2006-10-18 17:24:30 UTC (rev 70790)
@@ -33,7 +33,7 @@
 def test_suite():
     suite = unittest.TestSuite()
     for name in ['adapter', 'error', 'view', 'security', 'scan',
-                 'event', 'zcml', 'static', 'utility', 'xmlrpc']:
+                 'event', 'zcml', 'static', 'utility', 'xmlrpc', 'container']:
         suite.addTest(suiteFromPackage(name))
     return suite
 

Modified: grok/trunk/src/grok/util.py
===================================================================
--- grok/trunk/src/grok/util.py	2006-10-18 17:19:42 UTC (rev 70789)
+++ grok/trunk/src/grok/util.py	2006-10-18 17:24:30 UTC (rev 70790)
@@ -16,6 +16,7 @@
 
 import re
 import types
+import sys
 
 def not_unicode_or_ascii(value):
     if isinstance(value, unicode):
@@ -35,3 +36,6 @@
     if not isclass(obj):
         return False
     return issubclass(obj, class_)
+
+def caller_module():
+    return sys._getframe(2).f_globals['__name__']



More information about the Checkins mailing list