[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