[Checkins] SVN: zope.publisher/trunk/ Added a PasteDeploy
app_factory implementation. This should make
Jim Fulton
jim at zope.com
Sun Mar 2 18:25:38 EST 2008
Log message for revision 84419:
Added a PasteDeploy app_factory implementation. This should make
it easier to integrate Zope 3 applications with PasteDeploy. It
also makes it easier to control the publication used, giving far
greater control over application policies (e.g. whether or not to
use the ZODB).
Changed:
U zope.publisher/trunk/CHANGES.txt
U zope.publisher/trunk/setup.py
A zope.publisher/trunk/src/zope/publisher/paste.py
A zope.publisher/trunk/src/zope/publisher/paste.txt
A zope.publisher/trunk/src/zope/publisher/tests/test_paste.py
-=-
Modified: zope.publisher/trunk/CHANGES.txt
===================================================================
--- zope.publisher/trunk/CHANGES.txt 2008-03-02 22:41:47 UTC (rev 84418)
+++ zope.publisher/trunk/CHANGES.txt 2008-03-02 23:25:36 UTC (rev 84419)
@@ -2,9 +2,15 @@
CHANGES
=======
-After 3.4
----------
+3.5.0 (2008-03-02)
+------------------
+- Added a PasteDeploy app_factory implementation. This should make
+ it easier to integrate Zope 3 applications with PasteDeploy. It
+ also makes it easier to control the publication used, giving far
+ greater control over application policies (e.g. whether or not to
+ use the ZODB).
+
- Made segmentation of URLs not strip (trailing) whitespace from path segments
to allow URLs ending in %20 to be handled correctly. (#172742)
Modified: zope.publisher/trunk/setup.py
===================================================================
--- zope.publisher/trunk/setup.py 2008-03-02 22:41:47 UTC (rev 84418)
+++ zope.publisher/trunk/setup.py 2008-03-02 23:25:36 UTC (rev 84419)
@@ -18,6 +18,14 @@
import os
from setuptools import setup, find_packages
+entry_points = """
+[paste.app_factory]
+main = zope.publisher.paste:Application
+
+[zope.publisher.publication_factory]
+sample = zope.publisher.tests.test_paste:SamplePublication
+"""
+
setup(name='zope.publisher',
version = '3.5dev',
url='http://cheeseshop.python.org/pypi/zope.publisher',
@@ -27,6 +35,8 @@
description="The Zope publisher publishes Python objects on the web.",
long_description=open('README.txt').read(),
+ entry_points = entry_points,
+
packages=find_packages('src'),
package_dir = {'': 'src'},
Added: zope.publisher/trunk/src/zope/publisher/paste.py
===================================================================
--- zope.publisher/trunk/src/zope/publisher/paste.py (rev 0)
+++ zope.publisher/trunk/src/zope/publisher/paste.py 2008-03-02 23:25:36 UTC (rev 84419)
@@ -0,0 +1,67 @@
+##############################################################################
+#
+# Copyright (c) Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+import pkg_resources
+import zope.publisher.browser
+import zope.publisher.http
+import zope.publisher.publish
+
+browser_methods = set(('GET', 'HEAD', 'POST'))
+
+class Application:
+
+ def __init__(self, global_config, publication, **options):
+ if not publication.startswith('egg:'):
+ raise ValueError(
+ 'Invalid publication: .\n'
+ 'The publication specification must start with "egg:".\n'
+ 'The publication must name a publication entry point.'
+ % publication)
+
+ pub_class = get_egg(publication[4:],
+ 'zope.publisher.publication_factory')
+ self.publication = pub_class(global_config, **options)
+
+ def __call__(self, environ, start_response):
+ request = self.request(environ)
+ request.setPublication(self.publication)
+
+ # Let's support post-mortem debugging
+ handle_errors = environ.get('wsgi.handleErrors', True)
+
+ request = zope.publisher.publish.publish(
+ request, handle_errors=handle_errors)
+ response = request.response
+
+ # Start the WSGI server response
+ start_response(response.getStatusString(), response.getHeaders())
+
+ # Return the result body iterable.
+ return response.consumeBodyIter()
+
+ def request(self, environ):
+ method = environ.get('REQUEST_METHOD', 'GET').upper()
+ if method in browser_methods:
+ rc = zope.publisher.browser.BrowserRequest
+ else:
+ rc = zope.publisher.http.HTTPRequest
+ return rc(environ['wsgi.input'], environ)
+
+def get_egg(name, group):
+ if '#' in name:
+ egg, entry_point = name.split('#', 1)
+ else:
+ egg, entry_point = name, 'default'
+
+ return pkg_resources.load_entry_point(egg, group, entry_point)
Property changes on: zope.publisher/trunk/src/zope/publisher/paste.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.publisher/trunk/src/zope/publisher/paste.txt
===================================================================
--- zope.publisher/trunk/src/zope/publisher/paste.txt (rev 0)
+++ zope.publisher/trunk/src/zope/publisher/paste.txt 2008-03-02 23:25:36 UTC (rev 84419)
@@ -0,0 +1,90 @@
+===========================================
+Zope publisher integration with PasteDeploy
+===========================================
+
+PasteDeploy [#pastedeploy]_ provides a framework for assembling WSGI
+[#wsgi]_ components. It provides a framework for defining component
+factories that facilitates assembly based on simple configuration
+files. The zope.publisher package provides an application factory for
+defining publisher-based applications.
+
+To use in paste, you include a configuration section like::
+
+where:
+
+ [app:main]
+ use = egg:zope.publisher
+ publication = egg:zope.publisher#sample
+ foo = bar
+
+This example defines a "main" application using the zope.publisher
+factory. The only option required by zope.publisher is the
+publication option. This names an application-defined publication
+[#publication]_ factory. The factory is passed a dictionary of
+"global" options, as defined by PasteDeploy, and keyword arguments
+containing options from the application section, other than the use
+and publication options. In the example above, the foo option is
+passed.
+
+Detailed example
+================
+
+There's a sample publication class in
+zope.publisher.tests.test_paste.SamplePublication. It is a class that
+takes a global_config positional argument and arbitrary keyword
+arguments. It prints out this information as well as request data.
+It's registered as the "sample" entry point in the
+"zope.publisher.publication_factory" group.
+
+We can create a WSGI application for this sample publication by
+calling the zope.publisher.paste.Application factory. We'll get this
+by looking it up with package resources:
+
+ >>> import pkg_resources
+ >>> app_factory = pkg_resources.load_entry_point(
+ ... 'zope.publisher', 'paste.app_factory', 'main')
+
+ >>> app = app_factory(dict(global_option=42),
+ ... publication='egg:zope.publisher#sample',
+ ... app_option=1)
+
+Notice that we passed a publication name using the "egg" protocol.
+This is the only protocol currently supported.
+
+We can perform a test web request by calling the app factory with an
+environment dictionary and a start-response function:
+
+ >>> def start_response(status, headers):
+ ... print status
+ >>> import cStringIO
+ >>> env = {'CONTENT_TYPE': 'text/plain', 'PATH_INFO': '/a/b',
+ ... 'REQUEST_METHOD': 'GET', 'wsgi.input': cStringIO.StringIO('')}
+
+ >>> for data in app(env, start_response):
+ ... print data,
+ ... # doctest: +NORMALIZE_WHITESPACE
+ 200 Ok
+ <html><body>Thanks for your request:<br />
+ <h1>BrowserRequest</h1>
+ <pre>
+ CONTENT_TYPE: text/plain
+ PATH_INFO: /a/b
+ QUERY_STRING:
+ REQUEST_METHOD: GET
+ wsgi.input: <cStringIO.StringI object at 0xb7470a40>
+ </pre>
+ <h1>Publication arguments:</h1>
+ Globals: {'global_option': 42}<br />
+ Options: {'app_option': 1}
+ </body></html>
+
+
+
+.. [#paste] http://pythonpaste.org/deploy/
+
+.. [#wsgi] http://www.python.org/dev/peps/pep-0333/
+
+.. [#publication] Publications provide the interface between the
+ publisher and the application. See
+ zope.publisher.interfaces.IPublication and
+ zope.publisher.browser.interfaces.IBrowserPublication.
Property changes on: zope.publisher/trunk/src/zope/publisher/paste.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: zope.publisher/trunk/src/zope/publisher/tests/test_paste.py
===================================================================
--- zope.publisher/trunk/src/zope/publisher/tests/test_paste.py (rev 0)
+++ zope.publisher/trunk/src/zope/publisher/tests/test_paste.py 2008-03-02 23:25:36 UTC (rev 84419)
@@ -0,0 +1,70 @@
+##############################################################################
+#
+# Copyright (c) Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+import re, unittest
+from zope.testing import doctest, renormalizing
+
+class SamplePublication:
+
+ def __init__(self, global_config, **options):
+ self.args = global_config, options
+
+ def beforeTraversal(self, request):
+ pass
+
+ def getApplication(self, request):
+ return self
+
+ def callTraversalHooks(self, request, ob):
+ pass
+
+ def traverseName(self, request, ob, name):
+ return self
+
+ def afterTraversal(self, request, ob):
+ pass
+
+ def callObject(self, request, ob):
+ return (u'<html><body>Thanks for your request:<br />\n'
+ u'<h1>%s</h1>\n<pre>\n%s\n</pre>\n'
+ u'<h1>Publication arguments:</h1>\n'
+ u'Globals: %r<br />\nOptions: %r\n</body></html>'
+ % (request.__class__.__name__, request,
+ self.args[0], self.args[1])
+ )
+
+ def afterCall(self, request, ob):
+ pass
+
+ def handleException(self, object, request, exc_info, retry_allowed=1):
+ return 'Ouch!'
+
+ def endRequest(self, request, ob):
+ pass
+
+ def getDefaultTraversal(self, request, ob):
+ return self, ()
+
+def test_suite():
+ return unittest.TestSuite((
+ doctest.DocFileSuite(
+ '../paste.txt',
+ checker = renormalizing.RENormalizing([
+ (re.compile('at 0x[0-9a-f]+'), 'at <SOME ADDRESS>'),
+ ]),
+ ),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
+
Property changes on: zope.publisher/trunk/src/zope/publisher/tests/test_paste.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
More information about the Checkins
mailing list