[Checkins] SVN: grok/trunk/src/grok/ implemented grok.provides
(specify which interface to use in ambiguous cases) for
Adapter, MultiAdapter and GlobalUtility
Wolfgang Schnerring
wosc at wosc.de
Sat Jan 6 09:58:48 EST 2007
Log message for revision 71735:
implemented grok.provides (specify which interface to use in ambiguous cases) for Adapter, MultiAdapter and GlobalUtility
Changed:
U grok/trunk/src/grok/__init__.py
U grok/trunk/src/grok/directive.py
U grok/trunk/src/grok/interfaces.py
U grok/trunk/src/grok/meta.py
U grok/trunk/src/grok/tests/adapter/adapter.py
U grok/trunk/src/grok/tests/adapter/implementsmany.py
U grok/trunk/src/grok/tests/adapter/implementsnone.py
U grok/trunk/src/grok/tests/adapter/implementsnonemulti.py
U grok/trunk/src/grok/tests/adapter/multiadapter.py
A grok/trunk/src/grok/tests/utility/implementsmany.py
U grok/trunk/src/grok/tests/utility/implementsnone.py
U grok/trunk/src/grok/tests/utility/utility.py
U grok/trunk/src/grok/util.py
-=-
Modified: grok/trunk/src/grok/__init__.py
===================================================================
--- grok/trunk/src/grok/__init__.py 2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/__init__.py 2007-01-06 14:58:47 UTC (rev 71735)
@@ -33,7 +33,7 @@
from grok.components import Model, Adapter, MultiAdapter, View, XMLRPC
from grok.components import PageTemplate, GlobalUtility, Container, Traverser, Site
from grok.components import EditForm, DisplayForm, AddForm
-from grok.directive import context, name, template, templatedir
+from grok.directive import context, name, template, templatedir, provides
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/directive.py
===================================================================
--- grok/trunk/src/grok/directive.py 2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/directive.py 2007-01-06 14:58:47 UTC (rev 71735)
@@ -112,10 +112,20 @@
raise GrokImportError("You can only pass classes or interfaces to "
"%s." % self.name)
+class InterfaceDirective(Directive):
+ """
+ Directive that only accepts interface values.
+ """
+ def check(self, value):
+ if not (IInterface.providedBy(value)):
+ raise GrokImportError("You can only pass 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())
+provides = InterfaceDirective('grok.provides', ClassDirectiveContext())
Modified: grok/trunk/src/grok/interfaces.py
===================================================================
--- grok/trunk/src/grok/interfaces.py 2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/interfaces.py 2007-01-06 14:58:47 UTC (rev 71735)
@@ -79,6 +79,10 @@
of the directory. This can be overridden using
``templatedir``."""
+ def provides(interface):
+ """Explicitly specify with which interface a component will be looked up.
+ """
+
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 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/meta.py 2007-01-06 14:58:47 UTC (rev 71735)
@@ -33,30 +33,34 @@
def register(self, context, name, factory, module_info, templates):
adapter_context = util.determine_class_context(factory, context)
- util.check_implements_one(factory)
+ provides = util.class_annotation(factory, 'grok.provides', None)
+ if provides is None:
+ util.check_implements_one(factory)
name = util.class_annotation(factory, 'grok.name', '')
- try:
- component.provideAdapter(factory, adapts=(adapter_context,),
- name=name)
- except TypeError:
- import pdb; pdb.set_trace()
+ component.provideAdapter(factory, adapts=(adapter_context,),
+ provides=provides,
+ name=name)
class MultiAdapterGrokker(grok.ClassGrokker):
component_class = grok.MultiAdapter
def register(self, context, name, factory, module_info, templates):
- util.check_implements_one(factory)
+ provides = util.class_annotation(factory, 'grok.provides', None)
+ if provides is None:
+ util.check_implements_one(factory)
util.check_adapts(factory)
name = util.class_annotation(factory, 'grok.name', '')
- component.provideAdapter(factory, name=name)
+ component.provideAdapter(factory, provides=provides, name=name)
class GlobalUtilityGrokker(grok.ClassGrokker):
component_class = grok.GlobalUtility
def register(self, context, name, factory, module_info, templates):
- util.check_implements_one(factory)
+ provides = util.class_annotation(factory, 'grok.provides', None)
+ if provides is None:
+ util.check_implements_one(factory)
name = util.class_annotation(factory, 'grok.name', '')
- component.provideUtility(factory(), name=name)
+ component.provideUtility(factory(), provides=provides, name=name)
class XMLRPCGrokker(grok.ClassGrokker):
component_class = grok.XMLRPC
Modified: grok/trunk/src/grok/tests/adapter/adapter.py
===================================================================
--- grok/trunk/src/grok/tests/adapter/adapter.py 2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/tests/adapter/adapter.py 2007-01-06 14:58:47 UTC (rev 71735)
@@ -8,6 +8,12 @@
True
>>> isinstance(home, Home)
True
+
+ >>> fireplace = IFireplace(cave)
+ >>> IFireplace.providedBy(fireplace)
+ True
+ >>> isinstance(fireplace, Fireplace)
+ True
"""
import grok
@@ -21,3 +27,10 @@
class Home(grok.Adapter):
grok.implements(IHome)
+
+class IFireplace(interface.Interface):
+ pass
+
+class Fireplace(grok.Adapter):
+ grok.implements(IFireplace, IHome)
+ grok.provides(IFireplace)
Modified: grok/trunk/src/grok/tests/adapter/implementsmany.py
===================================================================
--- grok/trunk/src/grok/tests/adapter/implementsmany.py 2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/tests/adapter/implementsmany.py 2007-01-06 14:58:47 UTC (rev 71735)
@@ -5,7 +5,8 @@
>>> grok.grok(__name__)
Traceback (most recent call last):
...
- GrokError: <class 'grok.tests.adapter.implementsmany.Home'> must implement exactly one interface (use grok.implements to specify).
+ GrokError: <class 'grok.tests.adapter.implementsmany.Home'> is implementing
+ more than one interface (use grok.provides to specify which one to use).
"""
import grok
Modified: grok/trunk/src/grok/tests/adapter/implementsnone.py
===================================================================
--- grok/trunk/src/grok/tests/adapter/implementsnone.py 2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/tests/adapter/implementsnone.py 2007-01-06 14:58:47 UTC (rev 71735)
@@ -6,7 +6,7 @@
Traceback (most recent call last):
...
GrokError: <class 'grok.tests.adapter.implementsnone.Home'> must
- implement exactly one interface (use grok.implements to specify).
+ implement at least one interface (use grok.implements to specify).
"""
import grok
Modified: grok/trunk/src/grok/tests/adapter/implementsnonemulti.py
===================================================================
--- grok/trunk/src/grok/tests/adapter/implementsnonemulti.py 2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/tests/adapter/implementsnonemulti.py 2007-01-06 14:58:47 UTC (rev 71735)
@@ -6,7 +6,7 @@
Traceback (most recent call last):
...
GrokError: <class 'grok.tests.adapter.implementsnonemulti.Home'> must
- implement exactly one interface (use grok.implements to specify).
+ implement at least one interface (use grok.implements to specify).
"""
import grok
Modified: grok/trunk/src/grok/tests/adapter/multiadapter.py
===================================================================
--- grok/trunk/src/grok/tests/adapter/multiadapter.py 2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/tests/adapter/multiadapter.py 2007-01-06 14:58:47 UTC (rev 71735)
@@ -32,6 +32,20 @@
True
>>> home.fireplace is fireplace
True
+
+Multiadapters that implement more than one interface can use grok.provides to
+specify the one to use:
+
+ >>> home = component.getMultiAdapter((cave, fireplace), name='home3')
+
+ >>> IHome.providedBy(home)
+ True
+ >>> isinstance(home, Home3)
+ True
+ >>> home.cave is cave
+ True
+ >>> home.fireplace is fireplace
+ True
"""
import grok
@@ -62,3 +76,16 @@
def __init__(self, cave, fireplace):
self.cave = cave
self.fireplace = fireplace
+
+class IFireplace(interface.Interface):
+ pass
+
+class Home3(grok.MultiAdapter):
+ grok.adapts(Cave, Fireplace)
+ grok.implements(IHome, IFireplace)
+ grok.provides(IHome)
+ grok.name('home3')
+
+ def __init__(self, cave, fireplace):
+ self.cave = cave
+ self.fireplace = fireplace
Added: grok/trunk/src/grok/tests/utility/implementsmany.py
===================================================================
--- grok/trunk/src/grok/tests/utility/implementsmany.py 2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/tests/utility/implementsmany.py 2007-01-06 14:58:47 UTC (rev 71735)
@@ -0,0 +1,21 @@
+"""
+Subclasses of grok.GlobalUtility that implement more than one interface must
+specify which interface to use for the registration:
+
+ >>> grok.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: <class 'grok.tests.utility.implementsmany.Club'> is implementing
+ more than one interface (use grok.provides to specify which one to use).
+"""
+import grok
+from zope import interface
+
+class IClub(interface.Interface):
+ pass
+
+class ISpikyClub(interface.Interface):
+ pass
+
+class Club(grok.GlobalUtility):
+ grok.implements(IClub, ISpikyClub)
Modified: grok/trunk/src/grok/tests/utility/implementsnone.py
===================================================================
--- grok/trunk/src/grok/tests/utility/implementsnone.py 2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/tests/utility/implementsnone.py 2007-01-06 14:58:47 UTC (rev 71735)
@@ -5,7 +5,7 @@
Traceback (most recent call last):
...
GrokError: <class 'grok.tests.utility.implementsnone.Club'> must
- implement exactly one interface (use grok.implements to specify).
+ implement at least one interface (use grok.implements to specify).
"""
import grok
Modified: grok/trunk/src/grok/tests/utility/utility.py
===================================================================
--- grok/trunk/src/grok/tests/utility/utility.py 2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/tests/utility/utility.py 2007-01-06 14:58:47 UTC (rev 71735)
@@ -17,6 +17,27 @@
True
>>> isinstance(huge_club, HugeClub)
True
+
+A utility can explicitly specify which interface it should be looked up with.
+
+ >>> spiky_club = component.getUtility(IClub, name='spiky')
+ >>> isinstance(spiky_club, SpikyClub)
+ True
+
+ >>> component.getUtility(ISpikyClub, name='spiky')
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (<InterfaceClass grok.tests.utility.utility.ISpikyClub>,
+ 'spiky')
+
+If a utility implements more than one interface, it has to specify the one to
+use with 'grok.provides':
+
+ >>> nightclub = component.getUtility(INightClub)
+ >>> INightClub.providedBy(nightclub)
+ True
+ >>> isinstance(nightclub, NightClub)
+ True
"""
import grok
@@ -25,9 +46,24 @@
class IClub(interface.Interface):
pass
+class ISpikyClub(IClub):
+ pass
+
+class INightClub(interface.Interface):
+ pass
+
class NormalClub(grok.GlobalUtility):
grok.implements(IClub)
class HugeClub(grok.GlobalUtility):
grok.implements(IClub)
grok.name('huge')
+
+class SpikyClub(grok.GlobalUtility):
+ grok.implements(ISpikyClub)
+ grok.provides(IClub)
+ grok.name('spiky')
+
+class NightClub(grok.GlobalUtility):
+ grok.implements(INightClub, ISpikyClub)
+ grok.provides(INightClub)
Modified: grok/trunk/src/grok/util.py
===================================================================
--- grok/trunk/src/grok/util.py 2007-01-06 14:04:23 UTC (rev 71734)
+++ grok/trunk/src/grok/util.py 2007-01-06 14:58:47 UTC (rev 71735)
@@ -71,10 +71,14 @@
def check_implements_one(class_):
- if len(list(interface.implementedBy(class_))) != 1:
- raise GrokError("%r must implement exactly one interface "
+ if len(list(interface.implementedBy(class_))) < 1:
+ raise GrokError("%r must implement at least one interface "
"(use grok.implements to specify)."
% class_, class_)
+ elif len(list(interface.implementedBy(class_))) > 1:
+ raise GrokError("%r is implementing more than one interface "
+ "(use grok.provides to specify which one to use)."
+ % class_, class_)
def check_adapts(class_):
More information about the Checkins
mailing list