[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