[Checkins] SVN: grok/trunk/ Fix for https://bugs.launchpad.net/grok/+bug/305136 - REST skins should work like regular skins

Jan-Wijbrand Kolman janwijbrand at gmail.com
Mon Dec 15 16:12:30 EST 2008


Log message for revision 94086:
  Fix for https://bugs.launchpad.net/grok/+bug/305136 - REST skins should work like regular skins

Changed:
  U   grok/trunk/CHANGES.txt
  U   grok/trunk/doc/upgrade.txt
  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/rest/localgrants.py
  U   grok/trunk/src/grok/ftests/rest/rest.py
  U   grok/trunk/src/grok/ftests/rest/rest_traverse.py
  U   grok/trunk/src/grok/interfaces.py
  U   grok/trunk/src/grok/meta.py
  U   grok/trunk/src/grok/rest.py
  U   grok/trunk/src/grok/tests/conflict/rest.py

-=-
Modified: grok/trunk/CHANGES.txt
===================================================================
--- grok/trunk/CHANGES.txt	2008-12-15 21:10:40 UTC (rev 94085)
+++ grok/trunk/CHANGES.txt	2008-12-15 21:12:29 UTC (rev 94086)
@@ -10,6 +10,11 @@
 * Expose the ``DirectoryResource`` component from grokcore.view and the
   accompanying ``path`` directive.
 
+* Similar to the layers and skins restructuring, the ``grok.RESTProtocol``
+  baseclass has been removed in favour of a ``groke.restskin(name)`` directive
+  that can be used on REST layer interfaces. Introduced the IRESTRequest base
+  interfaces for defining REST layers.
+
 Bug fixes
 ---------
 

Modified: grok/trunk/doc/upgrade.txt
===================================================================
--- grok/trunk/doc/upgrade.txt	2008-12-15 21:10:40 UTC (rev 94085)
+++ grok/trunk/doc/upgrade.txt	2008-12-15 21:12:29 UTC (rev 94086)
@@ -6,6 +6,28 @@
 describes changes involving incompatibilities or deprecations, not new
 features (please refer to ``CHANGES.txt`` for those).
 
+Upgrading to 0.15
+-----------------
+
+* The ``grok.RESTProtocol`` class has been removed in favour of a
+  ``grok.restskin()`` directive for interfaces.  For instance, if you
+  previously registered a REST layer as a skin like so::
+
+    class IMyLayer(grok.IRESTLayer):
+        pass
+
+    class MyRestProtocol(grok.RESTProtocol):
+        grok.layer(IMyLayer)
+
+  You can now simply write::
+
+    class IMyLayer(grok.IRESTRequest):
+        grok.restskin('myskin')
+
+  As you can see, ``IRESTRequest`` has been introduced as a baseclass for
+  defining REST layers.
+
+
 Upgrading to 0.14
 -----------------
 
@@ -34,7 +56,7 @@
 
   A new Grok application will have an install_requires parameter that
   looks like this::
-  
+
       install_requires=['setuptools',
                         'grok',
                         'grokui.admin',
@@ -142,7 +164,7 @@
   the ``martian.component`` and the ``martian.priority`` directives
   that take the value as its first argument. The new
   ``martian.directive`` directive was introduced above.
- 
+
 * Custom directives need to be re-implemented using Martian's new
   ``Directive`` base class.  The directive scope, the type of storage,
   the validator and a potential default value are all defined as
@@ -217,7 +239,7 @@
 
     $ easy_install -U grokproject
 
-* If you have existing Grok projects and you want to make use of 
+* If you have existing Grok projects and you want to make use of
   Grok's new autoinclusion functionality in them, you can place
   the following line in your project's ``configure.zcml``:
 

Modified: grok/trunk/src/grok/__init__.py
===================================================================
--- grok/trunk/src/grok/__init__.py	2008-12-15 21:10:40 UTC (rev 94085)
+++ grok/trunk/src/grok/__init__.py	2008-12-15 21:12:29 UTC (rev 94086)
@@ -67,15 +67,13 @@
 from grok.components import Application, Form, AddForm, EditForm, DisplayForm
 from grok.components import Indexes
 from grok.components import Role
-from grok.components import RESTProtocol, IRESTLayer
-from grok.interfaces import IRESTSkinType
+from grok.interfaces import IRESTSkinType, IRESTRequest
 from grok.components import ViewletManager, Viewlet
 
-from grok.directive import (local_utility, permissions, site,
-                            viewletmanager, view, traversable, order)
+from grok.directive import (
+    local_utility, permissions, site, viewletmanager, view, restskin,
+    traversable, order)
 
-
-
 # BBB These two functions are meant for test fixtures and should be
 # imported from grok.testing, not from grok.
 from grok.testing import grok, grok_component

Modified: grok/trunk/src/grok/components.py
===================================================================
--- grok/trunk/src/grok/components.py	2008-12-15 21:10:40 UTC (rev 94085)
+++ grok/trunk/src/grok/components.py	2008-12-15 21:12:29 UTC (rev 94086)
@@ -196,10 +196,9 @@
         # if we have a RESTful request, we will handle
         # GET, POST and HEAD differently (PUT and DELETE are handled already
         # but not on the BrowserRequest layer but the HTTPRequest layer)
-        if IRESTLayer.providedBy(request):
+        if interfaces.IRESTRequest.providedBy(request):
             rest_view = component.getMultiAdapter(
-                (self.context, self.request),
-                name=request.method)
+                (self.context, self.request), name=request.method)
             return rest_view, ()
         view_name = getDefaultViewName(self.context, request)
         view_uri = "@@%s" % view_name
@@ -285,12 +284,7 @@
 class Role(Role):
     pass
 
-class IRESTLayer(IBrowserRequest):
-    pass
 
-class RESTProtocol(object):
-    pass
-
 class ViewletManager(ViewletManagerBase):
     interface.implements(interfaces.IViewletManager)
 

Modified: grok/trunk/src/grok/directive.py
===================================================================
--- grok/trunk/src/grok/directive.py	2008-12-15 21:10:40 UTC (rev 94085)
+++ grok/trunk/src/grok/directive.py	2008-12-15 21:12:29 UTC (rev 94086)
@@ -27,6 +27,7 @@
 from martian.error import GrokImportError, GrokError
 from martian.directive import StoreOnce, StoreMultipleTimes
 from grokcore.component.scan import UnambiguousComponentScope
+from grokcore.view.directive import TaggedValueStoreOnce
 from grok import components
 
 class local_utility(martian.Directive):
@@ -141,3 +142,13 @@
     def factory(self, value=0):
         order._order += 1
         return value, order._order
+
+class restskin(martian.Directive):
+    # We cannot do any better than to check for a class scope. Ideally we
+    # would've checked whether the context is indeed an Interface class.
+    scope = martian.CLASS
+    store = TaggedValueStoreOnce()
+    validate = martian.validateText
+
+    def factory(self, value=None):
+        return value

Modified: grok/trunk/src/grok/ftests/rest/localgrants.py
===================================================================
--- grok/trunk/src/grok/ftests/rest/localgrants.py	2008-12-15 21:10:40 UTC (rev 94085)
+++ grok/trunk/src/grok/ftests/rest/localgrants.py	2008-12-15 21:12:29 UTC (rev 94086)
@@ -1,7 +1,7 @@
 """
 REST objects, like all views, are properly located objects and will
 therefore honour local grants, for instance.  Let's consider the
-following model in the root folder.  
+following model in the root folder.
 
   >>> root = getRootFolder()
   >>> root['manfred'] = manfred = Mammoth('manfred')
@@ -57,13 +57,9 @@
     def __init__(self, name):
         self.name = name
 
-class MammothRestLayer(grok.IRESTLayer):
-    pass
+class MammothRestLayer(grok.IRESTRequest):
+    grok.restskin('mammoth')
 
-class MammothRestProtocol(grok.RESTProtocol):
-    grok.layer(MammothRestLayer)
-    grok.name('mammoth')
-
 class TouchMammoth(grok.Permission):
     grok.name('mammoth.Touch')
 

Modified: grok/trunk/src/grok/ftests/rest/rest.py
===================================================================
--- grok/trunk/src/grok/ftests/rest/rest.py	2008-12-15 21:10:40 UTC (rev 94085)
+++ grok/trunk/src/grok/ftests/rest/rest.py	2008-12-15 21:12:29 UTC (rev 94086)
@@ -302,45 +302,27 @@
 class MyContent(grok.Model):
     pass
 
-class LayerA(grok.IRESTLayer):
-    pass
+class LayerA(grok.IRESTRequest):
+    grok.restskin('a')
 
-class LayerB(grok.IRESTLayer):
-    pass
+class LayerB(grok.IRESTRequest):
+    grok.restskin('b')
 
-class LayerC(grok.IRESTLayer):
-    pass
+class LayerC(grok.IRESTRequest):
+    grok.restskin('c')
 
-class LayerSecurity(grok.IRESTLayer):
-    pass
+class LayerSecurity(grok.IRESTRequest):
+    grok.restskin('e')
 
-class LayerContent(grok.IRESTLayer):
-    pass
+class LayerContent(grok.IRESTRequest):
+    grok.restskin('f')
 
-class LayerInterface(grok.IRESTLayer):
-    pass
+class LayerInterface(grok.IRESTRequest):
+    grok.restskin('g')
 
-class A(grok.RESTProtocol):
-    grok.layer(LayerA)
+class D(grok.IRESTRequest):
+    grok.restskin('d')
 
-class B(grok.RESTProtocol):
-    grok.layer(LayerB)
-
-class C(grok.RESTProtocol):
-    grok.layer(LayerC)
-
-class D(grok.RESTProtocol):
-    grok.layer(grok.IRESTLayer)
-
-class E(grok.RESTProtocol):
-    grok.layer(LayerSecurity)
-
-class F(grok.RESTProtocol):
-    grok.layer(LayerContent)
-
-class G(grok.RESTProtocol):
-    grok.layer(LayerInterface)
-
 class ARest(grok.REST):
     grok.layer(LayerA)
     grok.context(MyApp)

Modified: grok/trunk/src/grok/ftests/rest/rest_traverse.py
===================================================================
--- grok/trunk/src/grok/ftests/rest/rest_traverse.py	2008-12-15 21:10:40 UTC (rev 94085)
+++ grok/trunk/src/grok/ftests/rest/rest_traverse.py	2008-12-15 21:12:29 UTC (rev 94086)
@@ -77,16 +77,13 @@
         if 'sub':
             return MyContent()
 
-class LayerZ(grok.IRESTLayer):
-    pass
+class LayerZ(grok.IRESTRequest):
+    grok.restskin('layerz')
 
-class Z(grok.RESTProtocol):
-    grok.layer(LayerZ)
-
 class ZContentRest(grok.REST):
     grok.layer(LayerZ)
     grok.context(MyContent)
-    
+
     def GET(self):
         return "GET content"
 

Modified: grok/trunk/src/grok/interfaces.py
===================================================================
--- grok/trunk/src/grok/interfaces.py	2008-12-15 21:10:40 UTC (rev 94085)
+++ grok/trunk/src/grok/interfaces.py	2008-12-15 21:12:29 UTC (rev 94086)
@@ -16,6 +16,7 @@
 from zope import interface, schema
 from zope.formlib.interfaces import reConstraint
 from zope.interface.interfaces import IInterface
+from zope.publisher.interfaces.http import IHTTPRequest
 from zope.viewlet.interfaces import IViewletManager as IViewletManagerBase
 from zope.app.container.interfaces import IContainer as IContainerBase
 
@@ -135,7 +136,7 @@
 class IGrokAPI(grokcore.security.interfaces.IGrokcoreSecurityAPI,
                grokcore.view.interfaces.IGrokcoreViewAPI,
                grokcore.formlib.interfaces.IGrokcoreFormlibAPI,
-               IGrokBaseClasses, IGrokDirectives, 
+               IGrokBaseClasses, IGrokDirectives,
                IGrokEvents, IGrokErrors):
 
     # BBB this is deprecated
@@ -221,6 +222,12 @@
         index for interface or class context.
         """
 
+class IRESTRequest(IHTTPRequest):
+    """REST-specific Request functionality.
+
+    Base Interfaces for defining REST-layers.
+    """
+
 class IRESTSkinType(IInterface):
     """Skin type for REST requests.
     """

Modified: grok/trunk/src/grok/meta.py
===================================================================
--- grok/trunk/src/grok/meta.py	2008-12-15 21:10:40 UTC (rev 94085)
+++ grok/trunk/src/grok/meta.py	2008-12-15 21:12:29 UTC (rev 94086)
@@ -15,6 +15,7 @@
 
 import zope.component.interface
 from zope import interface, component
+from zope.interface.interface import InterfaceClass
 from zope.publisher.interfaces.browser import (IDefaultBrowserLayer,
                                                IBrowserRequest,
                                                IBrowserPublisher)
@@ -111,7 +112,7 @@
 class RESTGrokker(martian.MethodGrokker):
     martian.component(grok.REST)
     martian.directive(grok.context)
-    martian.directive(grok.layer, default=grok.IRESTLayer)
+    martian.directive(grok.layer, default=grok.IRESTRequest)
     martian.directive(grok.require, name='permission')
 
     def execute(self, factory, method, config, permission, context, layer, **kw):
@@ -136,6 +137,36 @@
         return True
 
 
+_restskin_not_used = object()
+
+class RestskinInterfaceDirectiveGrokker(martian.InstanceGrokker):
+    martian.component(InterfaceClass)
+
+    def grok(self, name, interface, module_info, config, **kw):
+        restskin = grok.restskin.bind(default=_restskin_not_used).get(interface)
+        if restskin is _restskin_not_used:
+            # The restskin directive is not actually used on the found
+            # interface.
+            return False
+
+        if not interface.extends(grok.IRESTRequest):
+            # For REST layers it is required to extend IRESTRequest.
+            raise GrokError(
+                "The grok.restskin() directive is used on interface %r. "
+                "However, %r does not extend IRESTRequest which is "
+                "required for interfaces that are used as layers and are to "
+                "be registered as a restskin."
+                % (interface.__identifier__, interface.__identifier__),
+                interface
+                )
+        config.action(
+            discriminator=('restprotocol', restskin),
+            callable=zope.component.interface.provideInterface,
+            args=(restskin, interface, IRESTSkinType)
+            )
+        return True
+
+
 class JSONGrokker(martian.MethodGrokker):
     martian.component(grok.JSON)
     martian.directive(grok.context)
@@ -426,19 +457,6 @@
         return intids
 
 
-class RESTProtocolGrokker(martian.ClassGrokker):
-    martian.component(grok.RESTProtocol)
-    martian.directive(grok.layer, default=IBrowserRequest)
-    martian.directive(grok.name, get_default=default_view_name)
-
-    def execute(self, factory, config, name, layer, **kw):
-        config.action(
-            discriminator=('restprotocol', name),
-            callable=zope.component.interface.provideInterface,
-            args=(name, layer, IRESTSkinType)
-            )
-        return True
-
 class ViewletManagerGrokker(martian.ClassGrokker):
     martian.component(grok.ViewletManager)
     martian.directive(grok.context)

Modified: grok/trunk/src/grok/rest.py
===================================================================
--- grok/trunk/src/grok/rest.py	2008-12-15 21:10:40 UTC (rev 94085)
+++ grok/trunk/src/grok/rest.py	2008-12-15 21:12:29 UTC (rev 94086)
@@ -6,7 +6,7 @@
 
 """
 import grok
-from grok.interfaces import IRESTSkinType
+from grok.interfaces import IRESTSkinType, IRESTRequest
 
 from zope import component
 from zope.component.interfaces import ComponentLookupError
@@ -90,7 +90,7 @@
     clients attempt to assail them with unwanted HTTP methods.
 
     """
-    grok.layer(grok.IRESTLayer)
+    grok.layer(grok.IRESTRequest)
     grok.context(Interface)
 
     is_not_allowed = True

Modified: grok/trunk/src/grok/tests/conflict/rest.py
===================================================================
--- grok/trunk/src/grok/tests/conflict/rest.py	2008-12-15 21:10:40 UTC (rev 94085)
+++ grok/trunk/src/grok/tests/conflict/rest.py	2008-12-15 21:12:29 UTC (rev 94086)
@@ -10,8 +10,8 @@
 
 import grok
 
-class Protocol1(grok.RESTProtocol):
-    grok.name('foo')
+class Protocol1(grok.IRESTRequest):
+    grok.restskin('foo')
 
-class Protocol2(grok.RESTProtocol):
-    grok.name('foo')
+class Protocol2(grok.IRESTRequest):
+    grok.restskin('foo')



More information about the Checkins mailing list