[Checkins] SVN: grok/trunk/ REST now works properly with custom
traversal behavior. XML-RPC works
Martijn Faassen
faassen at infrae.com
Wed Apr 16 10:08:38 EDT 2008
Log message for revision 85438:
REST now works properly with custom traversal behavior. XML-RPC works
too.
Changed:
U grok/trunk/CHANGES.txt
U grok/trunk/src/grok/components.py
U grok/trunk/src/grok/ftests/rest/rest.py
A grok/trunk/src/grok/ftests/rest/rest_traverse.py
U grok/trunk/src/grok/ftests/xmlrpc/xmlrpc.py
U grok/trunk/src/grok/meta.py
-=-
Modified: grok/trunk/CHANGES.txt
===================================================================
--- grok/trunk/CHANGES.txt 2008-04-16 13:06:40 UTC (rev 85437)
+++ grok/trunk/CHANGES.txt 2008-04-16 14:08:38 UTC (rev 85438)
@@ -82,6 +82,10 @@
name, but this is actually a conflict. Now give configuration
conflict error when someone tries this.
+* Overriding traversal behavior using the ``traverse()`` method or
+ ``grok.Traverser`` failed in the face of (REST) ``PUT`` and
+ ``DELETE``. XML-RPC also failed when custom traversal was in use.
+
Restructuring
-------------
Modified: grok/trunk/src/grok/components.py
===================================================================
--- grok/trunk/src/grok/components.py 2008-04-16 13:06:40 UTC (rev 85437)
+++ grok/trunk/src/grok/components.py 2008-04-16 14:08:38 UTC (rev 85438)
@@ -28,8 +28,8 @@
from zope.securitypolicy.role import Role
from zope.publisher.browser import BrowserPage
from zope.publisher.interfaces import NotFound
-from zope.publisher.interfaces.browser import (IBrowserPublisher,
- IBrowserRequest)
+from zope.publisher.interfaces.browser import IBrowserPublisher
+from zope.publisher.interfaces.http import IHTTPRequest
from zope.publisher.publish import mapply
from zope.pagetemplate import pagetemplate, pagetemplatefile
from zope.formlib import form
@@ -418,7 +418,7 @@
class ModelTraverser(Traverser):
- component.adapts(Model, IBrowserRequest)
+ component.adapts(Model, IHTTPRequest)
def traverse(self, name):
traverse = getattr(self.context, 'traverse', None)
@@ -427,7 +427,7 @@
class ContainerTraverser(Traverser):
- component.adapts(Container, IBrowserRequest)
+ component.adapts(Container, IHTTPRequest)
def traverse(self, name):
traverse = getattr(self.context, 'traverse', None)
Modified: grok/trunk/src/grok/ftests/rest/rest.py
===================================================================
--- grok/trunk/src/grok/ftests/rest/rest.py 2008-04-16 13:06:40 UTC (rev 85437)
+++ grok/trunk/src/grok/ftests/rest/rest.py 2008-04-16 14:08:38 UTC (rev 85438)
@@ -235,15 +235,8 @@
We shouldn't be allowed to PUT either::
>>> print http('PUT /app/beta HTTP/1.1')
- HTTP/1. 500 Internal Server Error
- Content-Length: 127
- Content-Type: text/html;charset=utf-8
- <BLANKLINE>
- <html><head><title>ForbiddenAttribute</title></head>
- <body><h2>ForbiddenAttribute</h2>
- A server error occurred.
- </body></html>
- <BLANKLINE>
+ HTTP/1. 404 Not Found
+ Content-Length: 0
XXX shouldn't this really give a FORBIDDEN response?
Added: grok/trunk/src/grok/ftests/rest/rest_traverse.py
===================================================================
--- grok/trunk/src/grok/ftests/rest/rest_traverse.py (rev 0)
+++ grok/trunk/src/grok/ftests/rest/rest_traverse.py 2008-04-16 14:08:38 UTC (rev 85438)
@@ -0,0 +1,100 @@
+"""
+Let's examine Grok's REST support in the context of custom traversal to
+verify that works. We set the REST protocol in the code instead of specifying
+it in the URL, just in time (when we traverse to the content object that
+supports REST).
+
+Let's create a simple application with REST support::
+
+ >>> from grok.ftests.rest.rest_traverse import MyApp
+ >>> root = getRootFolder()
+ >>> root['app'] = MyApp()
+
+Let's first look at the index view of the application object::
+
+ >>> response = http_call('GET', 'http://localhost/app')
+ >>> print response.getBody()
+ The index view
+
+Now let's look at the content subobject, which should use REST by default
+because we make sure we set the skin::
+
+ >>> response = http_call('GET', 'http://localhost/app/content')
+ >>> print response.getBody()
+ GET content
+
+The other methods should also work::
+
+ >>> response = http_call('POST', 'http://localhost/app/content')
+ >>> print response.getBody()
+ POST content
+
+ >>> response = http_call('PUT', 'http://localhost/app/content')
+ >>> print response.getBody()
+ PUT content
+
+ >>> response = http_call('DELETE', 'http://localhost/app/content')
+ >>> print response.getBody()
+ DELETE content
+
+Besides the Traverser, we also want to make sure our ``traverse`` method
+on content objects works::
+
+ >>> response = http_call('GET', 'http://localhost/app/content/sub')
+ >>> print response.getBody()
+ GET content
+ >>> response = http_call('PUT', 'http://localhost/app/content/sub')
+ >>> print response.getBody()
+ PUT content
+
+"""
+
+import grok
+from zope.interface import Interface
+from zope.publisher.http import applySkin
+
+class IFoo(Interface):
+ pass
+
+class MyApp(grok.Model, grok.Application):
+ pass
+
+class Traverser(grok.Traverser):
+ grok.context(MyApp)
+
+ def traverse(self, name):
+ if name == 'content':
+ applySkin(self.request, LayerZ, grok.IRESTSkinType)
+ return MyContent()
+
+class Index(grok.View):
+ grok.context(MyApp)
+ def render(self):
+ return "The index view"
+
+class MyContent(grok.Model):
+ def traverse(self, name):
+ if 'sub':
+ return MyContent()
+
+class LayerZ(grok.IRESTLayer):
+ pass
+
+class Z(grok.RESTProtocol):
+ grok.layer(LayerZ)
+
+class ZContentRest(grok.REST):
+ grok.layer(LayerZ)
+ grok.context(MyContent)
+
+ def GET(self):
+ return "GET content"
+
+ def POST(self):
+ return "POST content"
+
+ def PUT(self):
+ return "PUT content"
+
+ def DELETE(self):
+ return "DELETE content"
Modified: grok/trunk/src/grok/ftests/xmlrpc/xmlrpc.py
===================================================================
--- grok/trunk/src/grok/ftests/xmlrpc/xmlrpc.py 2008-04-16 13:06:40 UTC (rev 85437)
+++ grok/trunk/src/grok/ftests/xmlrpc/xmlrpc.py 2008-04-16 14:08:38 UTC (rev 85438)
@@ -9,18 +9,36 @@
>>> server.Manfred.dance()
"Manfred doesn't like to dance."
+Let's also check whether we can use XML-RPC with subobjects we
+traverse to::
+
+ >>> server.Manfred.baby.pounce()
+ 'baby pounced.'
+
"""
import grok
class Mammoth(grok.Model):
+ def traverse(self, name):
+ if name == 'baby':
+ return MammothBaby()
+
+class MammothBaby(grok.Model):
pass
-
class MammothRPC(grok.XMLRPC):
-
+ grok.context(Mammoth)
+
def stomp(self):
return '%s stomped.' % self.context.__name__
def dance(self):
return '%s doesn\'t like to dance.' % self.context.__name__
+
+class BabyRPC(grok.XMLRPC):
+ grok.context(MammothBaby)
+
+ def pounce(self):
+ return '%s pounced.' % self.context.__name__
+
Modified: grok/trunk/src/grok/meta.py
===================================================================
--- grok/trunk/src/grok/meta.py 2008-04-16 13:06:40 UTC (rev 85437)
+++ grok/trunk/src/grok/meta.py 2008-04-16 14:08:38 UTC (rev 85438)
@@ -22,6 +22,8 @@
IBrowserRequest,
IBrowserPublisher,
IBrowserSkinType)
+from zope.publisher.interfaces.http import IHTTPRequest
+
from zope.publisher.interfaces.xmlrpc import IXMLRPCRequest
from zope.viewlet.interfaces import IViewletManager, IViewlet
from zope.security.interfaces import IPermission
@@ -365,7 +367,7 @@
def grok(self, name, factory, module_info, config, **kw):
factory_context = get_context(module_info, factory)
- adapts = (factory_context, IBrowserRequest)
+ adapts = (factory_context, IHTTPRequest)
config.action(
discriminator=('adapter', adapts, IBrowserPublisher, ''),
More information about the Checkins
mailing list