[Checkins] SVN: grok/branches/0.12/ Backport from
grokcore.component 1.0.1:
Philipp von Weitershausen
philikon at philikon.de
Fri May 2 06:35:14 EDT 2008
Log message for revision 86078:
Backport from grokcore.component 1.0.1:
* The grokkers for adapters and global utilities did not use the
correct value for the *provided* interface in the configuration
action discriminator. Because of this, uninformative and
potentially wrong conflict errors would occur, as well as no
conflict where a conflict should have occurred.
* The grokker for the ``global_utility()`` directive did immediate
registrations instead of generating configuration actions.
Therefore it did not provoke ``ConflictErrors`` for conflicting
registrations.
Changed:
U grok/branches/0.12/CHANGES.txt
U grok/branches/0.12/src/grok/meta.py
A grok/branches/0.12/src/grok/tests/adapter/conflict.py
A grok/branches/0.12/src/grok/tests/utility/conflict.py
A grok/branches/0.12/src/grok/tests/utility/providesmany.py
A grok/branches/0.12/src/grok/tests/utility/providesmany2.py
A grok/branches/0.12/src/grok/tests/utility/providesnone.py
A grok/branches/0.12/src/grok/tests/utility/providesnone2.py
U grok/branches/0.12/src/grok/util.py
-=-
Modified: grok/branches/0.12/CHANGES.txt
===================================================================
--- grok/branches/0.12/CHANGES.txt 2008-05-02 10:31:49 UTC (rev 86077)
+++ grok/branches/0.12/CHANGES.txt 2008-05-02 10:35:13 UTC (rev 86078)
@@ -7,6 +7,17 @@
Bug fixes
---------
+* The grokkers for adapters and global utilities did not use the
+ correct value for the *provided* interface in the configuration
+ action discriminator. Because of this, uninformative and
+ potentially wrong conflict errors would occur, as well as no
+ conflict where a conflict should have occurred.
+
+* The grokker for the ``global_utility()`` directive did immediate
+ registrations instead of generating configuration actions.
+ Therefore it did not provoke ``ConflictErrors`` for conflicting
+ registrations.
+
* Removed quickly hacked testsetup code from grok.testing.
* Port fix of zope.formlib to correctly adapt the context to a FormField's
Modified: grok/branches/0.12/src/grok/meta.py
===================================================================
--- grok/branches/0.12/src/grok/meta.py 2008-05-02 10:31:49 UTC (rev 86077)
+++ grok/branches/0.12/src/grok/meta.py 2008-05-02 10:35:13 UTC (rev 86078)
@@ -55,6 +55,7 @@
from grok.util import check_module_component, determine_module_component
from grok.util import determine_class_component
from grok.util import determine_class_directive, public_methods_from_class
+from grok.util import check_provides_one
from grok.rest import RestPublisher
from grok.interfaces import IRESTSkinType
@@ -76,6 +77,7 @@
provides = util.class_annotation(factory, 'grok.provides', None)
if provides is None:
util.check_implements_one(factory)
+ provides = list(interface.implementedBy(factory))[0]
return provides
class ContextGrokker(martian.GlobalGrokker):
@@ -141,17 +143,24 @@
priority = 1100
def grok(self, name, factory, module_info, config, **kw):
- provides = get_provides(factory)
+ provides = util.class_annotation(factory, 'grok.provides', None)
+ direct = util.class_annotation(factory, 'grok.direct', False)
name = get_name(factory)
- direct = util.class_annotation(factory, 'grok.direct', False)
- if not direct:
- factory = factory()
+ if direct:
+ obj = factory
+ if provides is None:
+ check_provides_one(factory)
+ provides = list(interface.providedBy(factory))[0]
+ else:
+ obj = factory()
+ if provides is None:
+ provides = get_provides(factory)
config.action(
discriminator=('utility', provides, name),
callable=component.provideUtility,
- args=(factory, provides, name),
+ args=(obj, provides, name),
)
return True
@@ -555,15 +564,24 @@
infos = module_info.getAnnotation('grok.global_utility', [])
for info in infos:
- if info.provides is None:
- util.check_implements_one(info.factory)
+ provides = info.provides
+
if info.direct:
obj = info.factory
+ if provides is None:
+ check_provides_one(obj)
+ provides = list(interface.providedBy(obj))[0]
else:
obj = info.factory()
- component.provideUtility(obj,
- provides=info.provides,
- name=info.name)
+ if provides is None:
+ provides = get_provides(info.factory)
+
+ config.action(
+ discriminator=('utility', provides, info.name),
+ callable=component.provideUtility,
+ args=(obj, provides, info.name),
+ )
+
return True
Copied: grok/branches/0.12/src/grok/tests/adapter/conflict.py (from rev 86061, grokcore.component/trunk/src/grokcore/component/tests/adapter/conflict.py)
===================================================================
--- grok/branches/0.12/src/grok/tests/adapter/conflict.py (rev 0)
+++ grok/branches/0.12/src/grok/tests/adapter/conflict.py 2008-05-02 10:35:13 UTC (rev 86078)
@@ -0,0 +1,39 @@
+"""
+Registering two adapters for the same target interface should provoke
+a conflict, even if the interface is guessed (instead of being
+explicitly declared with grok.provides):
+
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ ConfigurationConflictError: Conflicting configuration actions
+ For: ('adapter', <InterfaceClass grok.tests.adapter.conflict.ICave>, <InterfaceClass grok.tests.adapter.conflict.IDecoration>, '')
+
+"""
+import grok
+from zope.interface import Interface
+
+class ICave(Interface):
+ pass
+
+class IDecoration(Interface):
+ pass
+
+class ICaveCleaning(Interface):
+ pass
+
+class Cave(object):
+ grok.implements(ICave)
+
+
+class ImplicitProvides(grok.Adapter):
+ """Here the provided interface is guessed because the class only
+ implements one interface."""
+ grok.context(ICave)
+ grok.implements(IDecoration)
+
+class ExplicitProvides(grok.Adapter):
+ """Here the provided interface is specific explicitly."""
+ grok.context(ICave)
+ grok.implements(IDecoration, ICaveCleaning)
+ grok.provides(IDecoration)
Copied: grok/branches/0.12/src/grok/tests/utility/conflict.py (from rev 86061, grokcore.component/trunk/src/grokcore/component/tests/utility/conflict.py)
===================================================================
--- grok/branches/0.12/src/grok/tests/utility/conflict.py (rev 0)
+++ grok/branches/0.12/src/grok/tests/utility/conflict.py 2008-05-02 10:35:13 UTC (rev 86078)
@@ -0,0 +1,89 @@
+"""
+Trying to register two utilities for the same interface (and
+potentially under the same name) will generate a configuration
+conflict:
+
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ ConfigurationConflictError: Conflicting configuration actions
+ For: ('utility', <InterfaceClass grok.tests.utility.conflict.IUtilityInterface>, 'class and module')
+ <BLANKLINE>
+ <BLANKLINE>
+ For: ('utility', <InterfaceClass grok.tests.utility.conflict.IUtilityInterface>, 'direct class')
+ <BLANKLINE>
+ <BLANKLINE>
+ For: ('utility', <InterfaceClass grok.tests.utility.conflict.IUtilityInterface>, 'explicit class')
+ <BLANKLINE>
+ <BLANKLINE>
+ For: ('utility', <InterfaceClass grok.tests.utility.conflict.IUtilityInterface>, 'implicit class')
+ <BLANKLINE>
+ <BLANKLINE>
+ For: ('utility', <InterfaceClass grok.tests.utility.conflict.IUtilityInterface>, 'mixed class')
+ <BLANKLINE>
+ <BLANKLINE>
+
+"""
+import grok
+from zope.interface import Interface, classProvides
+
+class IUtilityInterface(Interface):
+ pass
+
+class IAnotherInterface(Interface):
+ pass
+
+
+class Implicit1(grok.GlobalUtility):
+ grok.implements(IUtilityInterface)
+ grok.name('implicit class')
+
+class Implicit2(grok.GlobalUtility):
+ grok.implements(IUtilityInterface)
+ grok.name('implicit class')
+
+
+class Explicit1(grok.GlobalUtility):
+ grok.implements(IUtilityInterface, IAnotherInterface)
+ grok.provides(IUtilityInterface)
+ grok.name('explicit class')
+
+class Explicit2(grok.GlobalUtility):
+ grok.implements(IUtilityInterface, IAnotherInterface)
+ grok.provides(IUtilityInterface)
+ grok.name('explicit class')
+
+
+class Mixed1(grok.GlobalUtility):
+ grok.implements(IUtilityInterface, IAnotherInterface)
+ grok.provides(IUtilityInterface)
+ grok.name('mixed class')
+
+class Mixed2(grok.GlobalUtility):
+ grok.implements(IUtilityInterface)
+ grok.name('mixed class')
+
+
+class Direct1(grok.GlobalUtility):
+ classProvides(IUtilityInterface)
+ grok.name('direct class')
+ grok.direct()
+
+class Direct2(grok.GlobalUtility):
+ classProvides(IUtilityInterface)
+ grok.name('direct class')
+ grok.direct()
+
+
+class ClassLevel(grok.GlobalUtility):
+ """This utility inherits from Grok's base class and is registered
+ this way."""
+ grok.implements(IUtilityInterface)
+ grok.name('class and module')
+
+class ModuleLevel(object):
+ """This utility doesn't inherit from Grok's base class and is
+ registered explicitly using the module-level directive below."""
+ grok.implements(IUtilityInterface)
+
+grok.global_utility(ModuleLevel, name='class and module')
Copied: grok/branches/0.12/src/grok/tests/utility/providesmany.py (from rev 86061, grokcore.component/trunk/src/grokcore/component/tests/utility/providesmany.py)
===================================================================
--- grok/branches/0.12/src/grok/tests/utility/providesmany.py (rev 0)
+++ grok/branches/0.12/src/grok/tests/utility/providesmany.py 2008-05-02 10:35:13 UTC (rev 86078)
@@ -0,0 +1,24 @@
+"""
+Subclasses of grok.GlobalUtility that are supposed to be registered
+directly as utilities and which provide more than one interface must
+specify which interface to use for the registration:
+
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: <class 'grok.tests.utility.providesmany.Club'>
+ provides 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):
+ interface.classProvides(IClub, ISpikyClub)
+ grok.direct()
Copied: grok/branches/0.12/src/grok/tests/utility/providesmany2.py (from rev 86061, grokcore.component/trunk/src/grokcore/component/tests/utility/providesmany2.py)
===================================================================
--- grok/branches/0.12/src/grok/tests/utility/providesmany2.py (rev 0)
+++ grok/branches/0.12/src/grok/tests/utility/providesmany2.py 2008-05-02 10:35:13 UTC (rev 86078)
@@ -0,0 +1,25 @@
+"""
+Subclasses of grok.GlobalUtility that are supposed to be registered
+directly as utilities and which provide more than one interface must
+specify which interface to use for the registration:
+
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: <class 'grok.tests.utility.providesmany2.Club'>
+ provides 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(object):
+ interface.classProvides(IClub, ISpikyClub)
+
+grok.global_utility(Club, direct=True)
Copied: grok/branches/0.12/src/grok/tests/utility/providesnone.py (from rev 86061, grokcore.component/trunk/src/grokcore/component/tests/utility/providesnone.py)
===================================================================
--- grok/branches/0.12/src/grok/tests/utility/providesnone.py (rev 0)
+++ grok/branches/0.12/src/grok/tests/utility/providesnone.py 2008-05-02 10:35:13 UTC (rev 86078)
@@ -0,0 +1,14 @@
+"""
+Subclasses of grok.GlobalUtility must implement exactly one interface:
+
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: <class 'grok.tests.utility.providesnone.Club'>
+ must provide at least one interface (use zope.interface.classProvides
+ to specify).
+"""
+import grok
+
+class Club(grok.GlobalUtility):
+ grok.direct()
Copied: grok/branches/0.12/src/grok/tests/utility/providesnone2.py (from rev 86061, grokcore.component/trunk/src/grokcore/component/tests/utility/providesnone2.py)
===================================================================
--- grok/branches/0.12/src/grok/tests/utility/providesnone2.py (rev 0)
+++ grok/branches/0.12/src/grok/tests/utility/providesnone2.py 2008-05-02 10:35:13 UTC (rev 86078)
@@ -0,0 +1,16 @@
+"""
+Subclasses of grok.GlobalUtility must implement exactly one interface:
+
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: <class 'grok.tests.utility.providesnone2.Club'>
+ must provide at least one interface (use zope.interface.classProvides
+ to specify).
+"""
+import grok
+
+class Club(object):
+ pass
+
+grok.global_utility(Club, direct=True)
Modified: grok/branches/0.12/src/grok/util.py
===================================================================
--- grok/branches/0.12/src/grok/util.py 2008-05-02 10:31:49 UTC (rev 86077)
+++ grok/branches/0.12/src/grok/util.py 2008-05-02 10:35:13 UTC (rev 86078)
@@ -17,7 +17,7 @@
import urllib
import zope.location.location
-from zope import component
+from zope import component, interface
from zope.traversing.browser.interfaces import IAbsoluteURL
from zope.traversing.browser.absoluteurl import _safe as SAFE_URL_CHARACTERS
@@ -188,3 +188,14 @@
check_module_component(class_, component,
component_name, component_directive)
return component
+
+def check_provides_one(obj):
+ provides = list(interface.providedBy(obj))
+ if len(provides) < 1:
+ raise GrokError("%r must provide at least one interface "
+ "(use zope.interface.classProvides to specify)."
+ % obj, obj)
+ if len(provides) > 1:
+ raise GrokError("%r provides more than one interface "
+ "(use grok.provides to specify which one to use)."
+ % obj, obj)
More information about the Checkins
mailing list