[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