[Checkins] SVN: grokcore.rest/trunk/src/grokcore/rest/ checkpoint
Christian Klinger
cklinger at novareto.de
Thu Dec 16 05:00:39 EST 2010
Log message for revision 118958:
checkpoint
Changed:
U grokcore.rest/trunk/src/grokcore/rest/configure.zcml
U grokcore.rest/trunk/src/grokcore/rest/ftesting.zcml
U grokcore.rest/trunk/src/grokcore/rest/ftests/rest/rest.py
U grokcore.rest/trunk/src/grokcore/rest/ftests/test_grok_functional.py
U grokcore.rest/trunk/src/grokcore/rest/publication.py
D grokcore.rest/trunk/src/grokcore/rest/tests/
-=-
Modified: grokcore.rest/trunk/src/grokcore/rest/configure.zcml
===================================================================
--- grokcore.rest/trunk/src/grokcore/rest/configure.zcml 2010-12-16 09:58:13 UTC (rev 118957)
+++ grokcore.rest/trunk/src/grokcore/rest/configure.zcml 2010-12-16 10:00:39 UTC (rev 118958)
@@ -12,19 +12,15 @@
provides="zope.traversing.interfaces.ITraversable"
name="rest"
/>
- <!-- this overrides Zope 3's publication factories because they have
- the same name; we also need to change the priority because of
- the ZCML discriminator -->
-<!--
+
<publisher
- name="BROWSER"
- factory=".publication.GrokBrowserFactory"
- methods="GET POST HEAD"
+ name="HTTP"
+ factory=".publication.GrokHTTPFactory"
+ methods="*"
mimetypes="*"
- priority="11"
+ priority="1"
/>
--->
- <!-- need to grok this for some basic REST support -->
+
<grok:grok package=".rest" />
</configure>
Modified: grokcore.rest/trunk/src/grokcore/rest/ftesting.zcml
===================================================================
--- grokcore.rest/trunk/src/grokcore/rest/ftesting.zcml 2010-12-16 09:58:13 UTC (rev 118957)
+++ grokcore.rest/trunk/src/grokcore/rest/ftesting.zcml 2010-12-16 10:00:39 UTC (rev 118958)
@@ -12,15 +12,9 @@
<include package="grokcore.view" file="publication_security.zcml" />
<include package="grokcore.rest" />
+ <include package="zope.app.http.exception" />
- <browser:defaultView name="index.html" />
-
-<!--
- <browser:defaultView
- for="grokcore.content.IContext"
- name="index"
- />
--->
-
+ <browser:defaultView name="index.html" />
<grok:grok package=".ftests" />
+
</configure>
Modified: grokcore.rest/trunk/src/grokcore/rest/ftests/rest/rest.py
===================================================================
--- grokcore.rest/trunk/src/grokcore/rest/ftests/rest/rest.py 2010-12-16 09:58:13 UTC (rev 118957)
+++ grokcore.rest/trunk/src/grokcore/rest/ftests/rest/rest.py 2010-12-16 10:00:39 UTC (rev 118958)
@@ -1,6 +1,16 @@
"""
Let's examine Grok's REST support.
+ >>> from zope.publisher.browser import TestRequest
+ >>> from zope.component import getMultiAdapter
+ >>> from grokcore.rest.rest import GrokMethodNotAllowed
+
+ >>> erview = getMultiAdapter((GrokMethodNotAllowed(None, None),
+ ... TestRequest()), name="index.html")
+
+ >>> erview
+ <grokcore.rest.rest.MethodNotAllowedView object at 0...>
+
Let's create a simple application with REST support::
>>> from grokcore.rest.ftests.rest.rest import MyApp
@@ -52,7 +62,7 @@
>>> response = http_call('POST', 'http://localhost/++rest++b/app')
Traceback (most recent call last):
...
- GrokMethodNotAllowed: <grok.ftests.rest.rest.MyApp object at ...>,
+ GrokMethodNotAllowed: <grokcore.rest.ftests.rest.rest.MyApp object at ...>,
<zope.publisher.browser.BrowserRequest instance URL=http://localhost/++rest++b/app>
DELETE is also not defined, so we also expect a 405 error::
@@ -60,7 +70,7 @@
>>> response = http_call('DELETE', 'http://localhost/++rest++b/app')
Traceback (most recent call last):
...
- GrokMethodNotAllowed: <grok.ftests.rest.rest.MyApp object at ...>,
+ GrokMethodNotAllowed: <grokcore.rest.ftests.rest.rest.MyApp object at ...>,
<zope.publisher.http.HTTPRequest instance URL=http://localhost/++rest++b/app>
Let's examine protocol c where no method is allowed::
@@ -68,38 +78,38 @@
>>> response = http_call('GET', 'http://localhost/++rest++c/app')
Traceback (most recent call last):
...
- GrokMethodNotAllowed: <grok.ftests.rest.rest.MyApp object at ...
+ GrokMethodNotAllowed: <grokcore.rest.ftests.rest.rest.MyApp object at ...
>>> response = http_call('POST', 'http://localhost/++rest++c/app')
Traceback (most recent call last):
...
- GrokMethodNotAllowed: <grok.ftests.rest.rest.MyApp object at ...
+ GrokMethodNotAllowed: <grokcore.rest.ftests.rest.rest.MyApp object at ...
>>> response = http_call('PUT', 'http://localhost/++rest++c/app')
Traceback (most recent call last):
...
- GrokMethodNotAllowed: <grok.ftests.rest.rest.MyApp object at ...
+ GrokMethodNotAllowed: <grokcore.rest.ftests.rest.rest.MyApp object at ...
>>> response = http_call('DELETE', 'http://localhost/++rest++c/app')
Traceback (most recent call last):
...
- GrokMethodNotAllowed: <grok.ftests.rest.rest.MyApp object at ...
+ GrokMethodNotAllowed: <grokcore.rest.ftests.rest.rest.MyApp object at ...
Let's examine the default protocol d, where nothing should work as well::
>>> response = http_call('GET', 'http://localhost/++rest++d/app')
Traceback (most recent call last):
...
- GrokMethodNotAllowed: <grok.ftests.rest.rest.MyApp object at ...
+ GrokMethodNotAllowed: <grokcore.rest.ftests.rest.rest.MyApp object at ...
>>> response = http_call('POST', 'http://localhost/++rest++d/app')
Traceback (most recent call last):
...
- GrokMethodNotAllowed: <grok.ftests.rest.rest.MyApp object at ...
+ GrokMethodNotAllowed: <grokcore.rest.ftests.rest.rest.MyApp object at ...
>>> response = http_call('PUT', 'http://localhost/++rest++d/app')
Traceback (most recent call last):
...
- GrokMethodNotAllowed: <grok.ftests.rest.rest.MyApp object at ...
+ GrokMethodNotAllowed: <grokcore.rest.ftests.rest.rest.MyApp object at ...
>>> response = http_call('DELETE', 'http://localhost/++rest++d/app')
Traceback (most recent call last):
...
- GrokMethodNotAllowed: <grok.ftests.rest.rest.MyApp object at ...
+ GrokMethodNotAllowed: <grokcore.rest.ftests.rest.rest.MyApp object at ...
We have added support for GET for the ``alpha`` subobject only, in
the default rest layer::
@@ -113,7 +123,7 @@
>>> response = http_call('POST', 'http://localhost/++rest++d/app/alpha')
Traceback (most recent call last):
...
- GrokMethodNotAllowed: <grok.ftests.rest.rest.MyContent object at ...
+ GrokMethodNotAllowed: <grokcore.rest.ftests.rest.rest.MyContent object at ...
According to the HTTP spec, in case of a 405 Method Not Allowed error,
the response MUST include an Allow header containing a list of valid
Modified: grokcore.rest/trunk/src/grokcore/rest/ftests/test_grok_functional.py
===================================================================
--- grokcore.rest/trunk/src/grokcore/rest/ftests/test_grok_functional.py 2010-12-16 09:58:13 UTC (rev 118957)
+++ grokcore.rest/trunk/src/grokcore/rest/ftests/test_grok_functional.py 2010-12-16 10:00:39 UTC (rev 118958)
@@ -30,7 +30,7 @@
if data is not None:
request_string += '\r\n'
request_string += data
- return http(request_string, handle_errors=True)
+ return http(request_string, handle_errors=False)
def suiteFromPackage(name):
files = resource_listdir(__name__, name)
Modified: grokcore.rest/trunk/src/grokcore/rest/publication.py
===================================================================
--- grokcore.rest/trunk/src/grokcore/rest/publication.py 2010-12-16 09:58:13 UTC (rev 118957)
+++ grokcore.rest/trunk/src/grokcore/rest/publication.py 2010-12-16 10:00:39 UTC (rev 118958)
@@ -40,32 +40,44 @@
BrowserFactory, HTTPFactory)
+class GrokHTTPPublication(ZopePublicationSansProxy, HTTPPublication):
+ """Combines `HTTPPublication` with the Grok sans-proxy mixin.
-class GrokBrowserPublication(ZopePublicationSansProxy, BrowserPublication):
- """Combines `BrowserPublication` with the Grok sans-proxy mixin.
+ Because `HTTPPublication` provides its own, special `callObject()`
+ implementation, this subclass does the same, providing what is
+ basically the same call (you can verify, in fact, that most of its
+ lines were copied directly from the superclass's version) but with a
+ few extra lines added so that - as with the simpler `callObject()`
+ method in `ZopePublicationSansProxy` - it quickly places a security
+ proxy around the object, makes sure that this HTTP method is
+ permitted, and finally passes the bare object to the view that will
+ render it.
- In addition to the three methods that are overridden by the
- `ZopePublicationSansProxy`, this class overrides a fourth: the
- `getDefaultTraversal()` method, which strips the security proxy from
- the object being returned by the normal method.
-
"""
- def getDefaultTraversal(self, request, ob):
- obj, path = super(GrokBrowserPublication, self).getDefaultTraversal(
- request, ob)
- return removeSecurityProxy(obj), path
+ def callObject(self, request, ob):
+ orig = ob
+ if not IHTTPException.providedBy(ob):
+ ob = component.queryMultiAdapter((ob, request),
+ name=request.method)
+ checker = selectChecker(ob)
+ if checker is not None:
+ checker.check(ob, '__call__')
+ ob = getattr(ob, request.method, None)
+ if ob is None:
+ raise GrokMethodNotAllowed(orig, request)
+ return mapply(ob, request.getPositionalArguments(), request)
-class GrokBrowserFactory(BrowserFactory):
- """Returns the classes Grok uses for browser requests and publication.
+class GrokHTTPFactory(HTTPFactory):
+ """Returns the classes Grok uses for HTTP requests and publication.
When an instance of this class is called, it returns a 2-element
tuple containing:
- - The request class that Grok uses for browser requests.
- - The publication class that Grok uses to publish to a browser.
+ - The request class that Grok uses for HTTP requests.
+ - The publication class that Grok uses to publish to HTTP.
"""
def __call__(self):
- request, publication = super(GrokBrowserFactory, self).__call__()
- return request, GrokBrowserPublication
+ request, publication = super(GrokHTTPFactory, self).__call__()
+ return request, GrokHTTPPublication
More information about the checkins
mailing list