[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