------------------------------------------------------------
revno: 6720
committer: Barry Warsaw <[email protected]>
branch nick: restful
timestamp: Sat 2009-05-02 18:07:38 -0400
message:
Moving closer now.
* Use the source version of lazr.restful until it's cheeseshopped.
* IHasGet -> IResolvePathNames
* path_override -> None; we don't need this
* Simplify publication. We don't need anything fancy, except that what sucks
is that it seems like we need to unwrap the security proxy in callObject()
* Adaptation to IAbsoluteURL still doesn't work right.
added:
src/mailman/rest/urls.py
src/mailman/rest/webservice.py
modified:
buildout.cfg
src/mailman/interfaces/rest.py
src/mailman/rest/configuration.py
src/mailman/rest/configure.zcml
src/mailman/rest/publication.py
src/mailman/rest/root.py
src/mailman/rest/traverse.py
=== modified file 'buildout.cfg'
--- buildout.cfg 2009-04-02 20:19:00 +0000
+++ buildout.cfg 2009-05-02 22:07:38 +0000
@@ -4,7 +4,7 @@
tags
test
unzip = true
-develop = .
+develop = . /Users/barry/projects/lazr/lazr.restful
[interpreter]
recipe = zc.recipe.egg
=== modified file 'src/mailman/interfaces/rest.py'
--- src/mailman/interfaces/rest.py 2009-04-02 00:02:49 +0000
+++ src/mailman/interfaces/rest.py 2009-05-02 22:07:38 +0000
@@ -21,7 +21,7 @@
__metaclass__ = type
__all__ = [
- 'IHasGet',
+ 'IResolvePathNames',
]
@@ -29,8 +29,8 @@
-class IHasGet(Interface):
- """A marker interface objects that implement traversal with get()."""
+class IResolvePathNames(Interface):
+ """A marker interface objects that implement simple traversal."""
def get(name):
"""Traverse to a contained object."""
=== modified file 'src/mailman/rest/configuration.py'
--- src/mailman/rest/configuration.py 2009-04-02 20:44:25 +0000
+++ src/mailman/rest/configuration.py 2009-05-02 22:07:38 +0000
@@ -26,11 +26,12 @@
from lazr.restful.interfaces import IWebServiceConfiguration
+from zope.interface import implements
+from mailman import version
from mailman.config import config
from mailman.rest.publication import AdminWebServicePublication
from mailman.rest.root import AdminWebServiceRootResource
-from mailman.version import VERSION
@@ -43,7 +44,7 @@
def view_permission(self):
return config.webservice.view_permission
- path_override = 'admin'
+ path_override = None
@property
def use_https(self):
@@ -51,8 +52,8 @@
return config.webservice.use_https
# This should match the major.minor Mailman version.
- service_version_uri_prefix = '3.0'
- code_revision = VERSION
+ service_version_uri_prefix = '{0.MAJOR_REV}.{0.MINOR_REV}'.format(version)
+ code_revision = version.VERSION
@property
def show_tracebacks(self):
=== modified file 'src/mailman/rest/configure.zcml'
--- src/mailman/rest/configure.zcml 2009-04-02 20:44:25 +0000
+++ src/mailman/rest/configure.zcml 2009-05-02 22:07:38 +0000
@@ -6,16 +6,20 @@
<include package="zope.component" file="meta.zcml"/>
<include package="zope.security" file="meta.zcml"/>
<include package="lazr.restful" file="meta.zcml"/>
-
- <webservice:register module="mailman.interfaces.rest" />
-
- <adapter factory="mailman.rest.traverse.Traverse" />
-
- <adapter factory="mailman.rest.root.AdminWebServiceRootAbsoluteURL" />
+ <include package="lazr.restful" file="configure.zcml"/>
+
+ <webservice:register module="mailman.interfaces.system" />
+
+ <adapter factory="mailman.rest.urls.AbsoluteURLMapper" />
<adapter
factory="mailman.rest.root.AdminWebServiceRootAbsoluteURL"
name="absolute_url"
/>
+ <utility
+ factory="mailman.rest.configuration.AdminWebServiceConfiguration"
+ provides="lazr.restful.interfaces.IWebServiceConfiguration">
+ </utility>
+
</configure>
=== modified file 'src/mailman/rest/publication.py'
--- src/mailman/rest/publication.py 2009-04-02 23:43:19 +0000
+++ src/mailman/rest/publication.py 2009-05-02 22:07:38 +0000
@@ -28,80 +28,55 @@
import traceback
from lazr.restful.publisher import WebServicePublicationMixin
-from zope.component import getUtility, queryMultiAdapter
+from zope.component import queryMultiAdapter
from zope.interface import implements
-from zope.publisher.interfaces import IPublication, IPublishTraverse, NotFound
+from zope.publisher.interfaces import IPublication, NotFound
from zope.publisher.publish import mapply
-from zope.security.checker import ProxyFactory
from zope.security.management import endInteraction, newInteraction
+from mailman.interfaces.rest import IResolvePathNames
+
class Publication:
- """Very simple implementation of `IPublication`.
-
- The object pass to the constructor is returned by getApplication().
- """
+ """Very simple implementation of `IPublication`."""
implements(IPublication)
def __init__(self, application):
- """Create the test publication.
-
- The object at which traversal should start is passed as parameter.
- """
self.application = application
def beforeTraversal(self, request):
- """Sets the request as the current interaction.
-
- (It also ends any previous interaction, that's convenient when
- tests don't go through the whole request.)
- """
- endInteraction()
- newInteraction(request)
+ """See `IPublication`."""
+ pass
def getApplication(self, request):
- """Returns the application passed to the constructor."""
+ """See `IPublication`."""
return self.application
def callTraversalHooks(self, request, ob):
- """Does nothing."""
+ """See `IPublication`."""
+ pass
def traverseName(self, request, ob, name):
- """Traverse by looking at an `IPublishTraverse` adapter.
-
- The object is security wrapped.
- """
- # XXX flacoste 2009/03/06 bug=338831. This is copied from
- # zope.app.publication.publicationtraverse.PublicationTraverse.
- # This should really live in zope.publisher, we are copying because
- # we don't want to depend on zope.app stuff.
- # Namespace support was dropped.
- if name == '.':
- return ob
-
- if IPublishTraverse.providedBy(ob):
- ob2 = ob.publishTraverse(request, name)
- else:
- # self is marker.
- adapter = queryMultiAdapter(
- (ob, request), IPublishTraverse, default=self)
- if adapter is not self:
- ob2 = adapter.publishTraverse(request, name)
- else:
- raise NotFound(ob, name, request)
-
- return ProxyFactory(ob2)
+ """See `IPublication`."""
+ missing = object()
+ resolver = IResolvePathNames(ob, missing)
+ if resolver is missing:
+ raise NotFound(ob, name, request)
+ return ob.get(name)
def afterTraversal(self, request, ob):
- """Does nothing."""
+ pass
def callObject(self, request, ob):
"""Call the object, returning the result."""
+ # XXX Bad hack.
+ from zope.security.proxy import removeSecurityProxy
+ ob = removeSecurityProxy(ob)
return mapply(ob, request.getPositionalArguments(), request)
def afterCall(self, request, ob):
- """Does nothing."""
+ pass
def handleException(self, object, request, exc_info, retry_allowed=1):
"""Prints the exception."""
=== modified file 'src/mailman/rest/root.py'
--- src/mailman/rest/root.py 2009-04-02 23:43:19 +0000
+++ src/mailman/rest/root.py 2009-05-02 22:07:38 +0000
@@ -27,6 +27,7 @@
from lazr.restful import ServiceRootResource
+from lazr.restful.interfaces import ICollection
from zope.component import adapts
from zope.interface import implements
from zope.publisher.interfaces.browser import IDefaultBrowserLayer
@@ -34,15 +35,12 @@
from mailman.config import config
from mailman.core.system import system
-from mailman.interfaces.rest import IHasGet
class AdminWebServiceRootResource(ServiceRootResource):
"""The root of the Mailman RESTful admin web service."""
- implements(IHasGet)
-
def get(self, name):
"""See `IHasGet`."""
top_level = {
=== modified file 'src/mailman/rest/traverse.py'
--- src/mailman/rest/traverse.py 2009-04-02 20:44:25 +0000
+++ src/mailman/rest/traverse.py 2009-05-02 22:07:38 +0000
@@ -40,7 +40,6 @@
"""An implementation of `IPublishTraverse` that uses the get() method."""
implements(IPublishTraverse)
- adapts(IHasGet, IDefaultBrowserLayer)
def __init__(self, context, request):
self.context = context
=== added file 'src/mailman/rest/urls.py'
--- src/mailman/rest/urls.py 1970-01-01 00:00:00 +0000
+++ src/mailman/rest/urls.py 2009-05-02 22:07:38 +0000
@@ -0,0 +1,53 @@
+# Copyright (C) 2009 by the Free Software Foundation, Inc.
+#
+# This file is part of GNU Mailman.
+#
+# GNU Mailman is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
+
+"""Module stuff."""
+
+from __future__ import absolute_import, unicode_literals
+
+__metaclass__ = type
+__all__ = [
+ 'AbsoluteURLMapper',
+ ]
+
+
+from zope.component import adapts
+from zope.interface import implements, Interface
+from zope.traversing.browser.interfaces import IAbsoluteURL
+
+
+
+class AbsoluteURLMapper:
+ """Generic absolute url mapper."""
+
+ implements(IAbsoluteURL)
+ adapts(Interface, IAbsoluteURL)
+
+ def __init__(self, context, request):
+ """Initialize with respect to a context and request."""
+ # Avoid circular imports.
+ from mailman.rest.configuration import AdminWebServiceConfiguration
+ self.webservice_config = AdminWebServiceConfiguration()
+ self.version = webservice_config.service_version_uri_prefix
+ self.schema = ('https' if self.webservice_config.use_https else 'http')
+ self.hostname = config.webservice.hostname
+
+ def __str__(self):
+ """Return the semi-hard-coded URL to the service root."""
+ return '{0.schema}://{0.hostname}/{0.version}'.format(self)
+
+ __call__ = __str__
=== added file 'src/mailman/rest/webservice.py'
--- src/mailman/rest/webservice.py 1970-01-01 00:00:00 +0000
+++ src/mailman/rest/webservice.py 2009-05-02 22:07:38 +0000
@@ -0,0 +1,88 @@
+# Copyright (C) 2009 by the Free Software Foundation, Inc.
+#
+# This file is part of GNU Mailman.
+#
+# GNU Mailman is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
+
+"""Module stuff."""
+
+from __future__ import absolute_import, unicode_literals
+
+__metaclass__ = type
+__all__ = [
+ 'AdminWebServiceApplication',
+ 'AdminWebServiceRequest',
+ 'start',
+ ]
+
+
+from wsgiref.simple_server import make_server
+
+from lazr.restful.publisher import WebServiceRequestTraversal
+from pkg_resources import resource_string
+from zope.configuration import xmlconfig
+from zope.interface import implements
+from zope.publisher.browser import BrowserRequest
+from zope.publisher.publish import publish
+
+from mailman.core.system import system
+from mailman.interfaces.rest import IResolvePathNames
+from mailman.rest.publication import AdminWebServicePublication
+
+
+
+class AdminWebServiceRequest(WebServiceRequestTraversal, BrowserRequest):
+ """A request for the admin REST interface."""
+
+
+class AdminWebServiceApplication:
+ """A WSGI application for the admin REST interface."""
+
+ implements(IResolvePathNames)
+
+ def __init__(self, environ, start_response):
+ # Create the request based on the HTTP method used.
+ method = environ.get('REQUEST_METHOD', 'GET').upper()
+ request = AdminWebServiceRequest(environ['wsgi.input'], environ)
+ request.setPublication(AdminWebServicePublication(self))
+ # Support post-mortem debugging.
+ handle_errors = environ.get('wsgi.handleErrors', True)
+ # The request returned by the publisher may in fact be different than
+ # the one passed in.
+ request = publish(request, handle_errors=handle_errors)
+ # Start the WSGI server response.
+ response = request.response
+ start_response(response.getStatusString(), response.getHeaders())
+ # Return the result body iterable.
+ return response.consumeBodyIter()
+
+ def get(self, name):
+ """Maps root names to resources."""
+ top_level = dict(
+ sys=system,
+ )
+ return top_level.get(name)
+
+
+
+def start():
+ """Start the WSGI admin REST service."""
+ zcml = resource_string('mailman.rest', 'configure.zcml')
+ xmlconfig.string(zcml)
+ server = make_server('', 8001, AdminWebServiceApplication)
+ return server
+
+
+if __name__ == '__main__':
+ start().serve_forever()
--
Primary development focus
https://code.launchpad.net/~mailman-coders/mailman/3.0
Your team Mailman Checkins is subscribed to branch lp:mailman.
To unsubscribe from this branch go to
https://code.launchpad.net/~mailman-coders/mailman/3.0/+edit-subscription.
_______________________________________________
Mailman-checkins mailing list
[email protected]
Unsubscribe:
http://mail.python.org/mailman/options/mailman-checkins/archive%40jab.org