[Checkins] SVN: grok/trunk/src/grok/ Introduce ModuleGrokker and
priority for grokkers. This allows us to
Martijn Faassen
faassen at infrae.com
Tue Dec 12 15:08:47 EST 2006
Log message for revision 71541:
Introduce ModuleGrokker and priority for grokkers. This allows us to
get rid of the last bits in _grok that have to do with actual grokking
and move it over to meta.py.
ModuleGrokkers get executed once per module. This can then be used to
register filesystem templates, or various decorators, or static files if
the module happens to be a package.
Grokkers get a priority now. The higher the priority, the earlier in the
grokking process they're executed. We use this to make sure that some
grokkers get executed before others.
Changed:
U grok/trunk/src/grok/__init__.py
U grok/trunk/src/grok/_grok.py
U grok/trunk/src/grok/components.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 2006-12-12 17:48:40 UTC (rev 71540)
+++ grok/trunk/src/grok/__init__.py 2006-12-12 20:08:46 UTC (rev 71541)
@@ -29,7 +29,7 @@
IObjectRemovedEvent, ObjectRemovedEvent,
IContainerModifiedEvent, ContainerModifiedEvent)
-from grok.components import ClassGrokker, InstanceGrokker
+from grok.components import ClassGrokker, InstanceGrokker, ModuleGrokker
from grok.components import Model, Adapter, MultiAdapter, View, XMLRPC
from grok.components import PageTemplate, Utility, Container, Traverser, Site
from grok.components import EditForm, DisplayForm, AddForm
Modified: grok/trunk/src/grok/_grok.py
===================================================================
--- grok/trunk/src/grok/_grok.py 2006-12-12 17:48:40 UTC (rev 71540)
+++ grok/trunk/src/grok/_grok.py 2006-12-12 20:08:46 UTC (rev 71541)
@@ -18,10 +18,9 @@
from zope import component
from zope import interface
-import zope.component.interface
+
from zope.component.interfaces import IDefaultViewName
-from zope.publisher.interfaces.browser import (IDefaultBrowserLayer,
- IBrowserRequest)
+from zope.publisher.interfaces.browser import IBrowserRequest
from zope.app.component.site import LocalSiteManager
import grok
@@ -59,6 +58,8 @@
# the Component Architecture is torn down.
def resetBootstrap():
global _bootstrapped
+ # we need to make sure that the grokker registry is clean again
+ grokker.grokkerRegistry.clear()
_bootstrapped = False
from zope.testing.cleanup import addCleanUp
addCleanUp(resetBootstrap)
@@ -75,47 +76,11 @@
def grok_tree(module_info):
- grok_module(module_info)
+ grokker.grokkerRegistry.grok(module_info)
- if not module_info.isPackage():
- return
-
- resource_path = module_info.getResourcePath('static')
- if os.path.isdir(resource_path):
- static_module = module_info.getSubModuleInfo('static')
- if static_module is not None:
- if static_module.isPackage():
- raise GrokError("The 'static' resource directory must not "
- "be a python package.", module_info.getModule())
- else:
- raise GrokError("A package can not contain both a 'static' "
- "resource directory and a module named "
- "'static.py'", module_info.getModule())
-
- register_static_resources(module_info.dotted_name, resource_path)
-
for sub_module_info in module_info.getSubModuleInfos():
grok_tree(sub_module_info)
-
-def grok_module(module_info):
- grokker.grokkerRegistry.grok(module_info)
-
- # XXX we should ideally also make it pluggable to register decorators like
- # the ones for subscribers.
- register_subscribers(module_info.getAnnotation('grok.subscribers', []))
-
-def register_static_resources(dotted_name, resource_directory):
- resource_factory = components.DirectoryResourceFactory(resource_directory,
- dotted_name)
- component.provideAdapter(resource_factory, (IDefaultBrowserLayer,),
- interface.Interface, name=dotted_name)
-
-def register_subscribers(subscribers):
- for factory, subscribed in subscribers:
- component.provideHandler(factory, adapts=subscribed)
- for iface in subscribed:
- zope.component.interface.provideInterface('', iface)
-
+
# decorators
class SubscribeDecorator:
def __init__(self, *args):
Modified: grok/trunk/src/grok/components.py
===================================================================
--- grok/trunk/src/grok/components.py 2006-12-12 17:48:40 UTC (rev 71540)
+++ grok/trunk/src/grok/components.py 2006-12-12 20:08:46 UTC (rev 71541)
@@ -47,7 +47,11 @@
from grok import util, security, interfaces
class ClassGrokker(object):
+ """Grokker for particular classes in a module.
+ """
# subclasses should have a component_class class variable
+
+ priority = 0
def match(self, obj):
return util.check_subclass(obj, self.component_class)
@@ -57,7 +61,11 @@
class InstanceGrokker(object):
+ """Grokker for particular instances in a module.
+ """
# subclasses should have a component_class class variable
+
+ priority = 0
def match(self, obj):
return isinstance(obj, self.component_class)
@@ -66,6 +74,19 @@
raise NotImplementedError
+class ModuleGrokker(object):
+ """Grokker that gets executed once for a module.
+ """
+ priority = 0
+
+ def match(self, obj):
+ # we never match with any object
+ return False
+
+ def register(self, context, module_info, templates):
+ raise NotImplementedError
+
+
class Model(Contained, persistent.Persistent):
# XXX Inheritance order is important here. If we reverse this,
# then containers can't be models anymore because no unambigous MRO
Modified: grok/trunk/src/grok/grokker.py
===================================================================
--- grok/trunk/src/grok/grokker.py 2006-12-12 17:48:40 UTC (rev 71540)
+++ grok/trunk/src/grok/grokker.py 2006-12-12 20:08:46 UTC (rev 71541)
@@ -3,14 +3,23 @@
class GrokkerRegistry(object):
def __init__(self):
- self._grokkers = {}
+ self.clear()
+
+ def clear(self):
+ self._grokkers = []
+ # register the meta grokkers manually as we can't grok those
+ self.registerGrokker(ClassGrokkerGrokker())
+ self.registerGrokker(InstanceGrokkerGrokker())
+ self.registerGrokker(ModuleGrokkerGrokker())
def registerGrokker(self, grokker):
- self._grokkers[grokker.component_class] = grokker
+ self._grokkers.append(grokker)
def scan(self, module_info):
components = {}
- for grokker in self._grokkers.values():
+ for grokker in self._grokkers:
+ if isinstance(grokker, grok.ModuleGrokker):
+ continue
components[grokker.component_class] = []
module = module_info.getModule()
@@ -22,7 +31,7 @@
continue
# XXX find way to get rid of this inner loop by doing hash table
# lookup?
- for grokker in self._grokkers.values():
+ for grokker in self._grokkers:
if grokker.match(obj):
components[grokker.component_class].append((name, obj))
break
@@ -41,37 +50,33 @@
templates = templatereg.TemplateRegistry()
- # XXX because templates are instances and we need access to
- # registered module-level templates during class grokking,
- # we need to make sure we do PageTemplate grokking before any
- # other grokking. We need to revise this as we work out
- # extensible template grokking. Possibly we need to introduce
- # a priority for grokkers so we can sort them.
- page_templates = scanned_results.pop(grok.PageTemplate, None)
- if page_templates is not None:
- grokker = self._grokkers[grok.PageTemplate]
- for name, component in page_templates:
+ # sort grokkers by priority
+ grokkers = sorted(self._grokkers,
+ key=lambda grokker: grokker.priority)
+ # we want to handle high priority first
+ grokkers.reverse()
+
+ # run through all grokkers registering found components in order
+ for grokker in grokkers:
+ # if we run into a ModuleGrokker, just do simple registration.
+ # this allows us to hook up grokkers to the process that actually
+ # do not respond to anything in the module but for instance
+ # to the filesystem to find templates
+ if isinstance(grokker, grok.ModuleGrokker):
+ grokker.register(context, module_info, templates)
+ continue
+
+ components = scanned_results.get(grokker.component_class, [])
+ for name, component in components:
grokker.register(context,
name, component,
module_info, templates)
- # XXX filesystem level templates need to be scanned for after
- # inline templates to produce the right errors
- templates.findFilesystem(module_info)
-
- # now grok the rest
- for component_class, components in scanned_results.items():
- grokker = self._grokkers[component_class]
- for name, component in components:
- grokker.register(context,
- name, component,
- module_info, templates)
-
templates.registerUnassociated(context, module_info)
-# deep meta mode here - we define grokkers for grok.ClassGrokker and
-# grok.InstanceGrokker.
+# deep meta mode here - we define grokkers for grok.ClassGrokker,
+# grok.InstanceGrokker, and grokker.ModuleGrokker.
class MetaGrokker(grok.ClassGrokker):
def register(self, context, name, factory, module_info, templates):
@@ -83,9 +88,9 @@
class InstanceGrokkerGrokker(MetaGrokker):
component_class = grok.InstanceGrokker
+class ModuleGrokkerGrokker(MetaGrokker):
+ component_class = grok.ModuleGrokker
+
# the global grokker registry
grokkerRegistry = GrokkerRegistry()
-# register the meta grokkers manually as we can't grok those
-grokkerRegistry.registerGrokker(ClassGrokkerGrokker())
-grokkerRegistry.registerGrokker(InstanceGrokkerGrokker())
Modified: grok/trunk/src/grok/interfaces.py
===================================================================
--- grok/trunk/src/grok/interfaces.py 2006-12-12 17:48:40 UTC (rev 71540)
+++ grok/trunk/src/grok/interfaces.py 2006-12-12 20:08:46 UTC (rev 71541)
@@ -20,6 +20,8 @@
"grokker.")
InstanceGrokker = interface.Attribute("Base class to define an "
"instance grokker.")
+ ModuleGrokker = interface.Attribute("Base class to define a "
+ "module grokker.")
Model = interface.Attribute("Base class for persistent content objects "
"(models).")
Container = interface.Attribute("Base class for containers.")
Modified: grok/trunk/src/grok/meta.py
===================================================================
--- grok/trunk/src/grok/meta.py 2006-12-12 17:48:40 UTC (rev 71540)
+++ grok/trunk/src/grok/meta.py 2006-12-12 20:08:46 UTC (rev 71541)
@@ -1,5 +1,7 @@
+import os
import inspect
+import zope.component.interface
from zope import interface, component
from zope.security.checker import (defineChecker, getCheckerForInstancesOf,
NoProxy)
@@ -166,10 +168,62 @@
component.provideAdapter(factory,
adapts=(factory_context, IBrowserRequest),
provides=IBrowserPublisher)
-
-class PageTemplateGrokker(grok.InstanceGrokker):
+
+class ModulePageTemplateGrokker(grok.InstanceGrokker):
+ # this needs to happen before any other grokkers execute that actually
+ # use the templates
+ priority = 1000
+
component_class = grok.PageTemplate
def register(self, context, name, instance, module_info, templates):
templates.register(name, instance)
instance._annotateGrokInfo(name, module_info.dotted_name)
+
+class FilesystemPageTemplateGrokker(grok.ModuleGrokker):
+ # do this early on, but after ModulePageTemplateGrokker, as
+ # findFilesystem depends on module-level templates to be
+ # already grokked for error reporting
+ priority = 999
+
+ def register(self, context, module_info, templates):
+ templates.findFilesystem(module_info)
+
+class SubscriberGrokker(grok.ModuleGrokker):
+
+ def register(self, context, module_info, templates):
+ subscribers = module_info.getAnnotation('grok.subscribers', [])
+
+ for factory, subscribed in subscribers:
+ component.provideHandler(factory, adapts=subscribed)
+ for iface in subscribed:
+ zope.component.interface.provideInterface('', iface)
+
+class StaticResourcesGrokker(grok.ModuleGrokker):
+
+ def register(self, context, module_info, templates):
+ # we're only interested in static resources if this module
+ # happens to be a package
+ if not module_info.isPackage():
+ return
+
+ resource_path = module_info.getResourcePath('static')
+ if os.path.isdir(resource_path):
+ static_module = module_info.getSubModuleInfo('static')
+ if static_module is not None:
+ if static_module.isPackage():
+ raise GrokError(
+ "The 'static' resource directory must not "
+ "be a python package.",
+ module_info.getModule())
+ else:
+ raise GrokError(
+ "A package can not contain both a 'static' "
+ "resource directory and a module named "
+ "'static.py'", module_info.getModule())
+
+ resource_factory = components.DirectoryResourceFactory(
+ resource_path, module_info.dotted_name)
+ component.provideAdapter(
+ resource_factory, (IDefaultBrowserLayer,),
+ interface.Interface, name=module_info.dotted_name)
More information about the Checkins
mailing list