[Checkins] SVN: Sandbox/shane/republish/zope/pipeline/ Moved to a two-step application creation process.
Shane Hathaway
shane at hathawaymix.org
Sat Feb 14 03:50:38 EST 2009
Log message for revision 96519:
Moved to a two-step application creation process.
All sorts of goodness suddenly fell out:
- There is an easy way to pass app construction parameters.
- Multi-adaptation is no longer needed.
- The distinction between the wsgi:application and wsgi:middleware is
no longer useful, so there is now just wsgi:application.
- The need for a module level pipeline cache disappeared. Pipeline
caching is now done in an instance of the SwitchPipeline application.
- There is no longer a risk of bugs caused by applications not
providing the IWSGIApplication interface, since the pipeline
builder is no longer aware of IWSGIApplication.
Also renamed self.app to self.next_app in most of the middleware apps.
Changed:
U Sandbox/shane/republish/zope/pipeline/apps/authenticate.py
U Sandbox/shane/republish/zope/pipeline/apps/event.py
U Sandbox/shane/republish/zope/pipeline/apps/fixrel.py
U Sandbox/shane/republish/zope/pipeline/apps/openroot.py
U Sandbox/shane/republish/zope/pipeline/apps/requestsetup.py
U Sandbox/shane/republish/zope/pipeline/apps/retry.py
U Sandbox/shane/republish/zope/pipeline/apps/switch.py
U Sandbox/shane/republish/zope/pipeline/apps/traversal.py
U Sandbox/shane/republish/zope/pipeline/apps/txnctl.py
U Sandbox/shane/republish/zope/pipeline/configure.zcml
U Sandbox/shane/republish/zope/pipeline/entry.py
U Sandbox/shane/republish/zope/pipeline/interfaces.py
U Sandbox/shane/republish/zope/pipeline/meta.zcml
U Sandbox/shane/republish/zope/pipeline/zcml.py
-=-
Modified: Sandbox/shane/republish/zope/pipeline/apps/authenticate.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/apps/authenticate.py 2009-02-14 07:14:39 UTC (rev 96518)
+++ Sandbox/shane/republish/zope/pipeline/apps/authenticate.py 2009-02-14 08:50:36 UTC (rev 96519)
@@ -13,7 +13,6 @@
##############################################################################
from zope.component import getGlobalSiteManager
-from zope.interface import adapts
from zope.interface import implements
from zope.publisher.interfaces import IWSGIApplication
from zope.security.management import newInteraction
@@ -29,10 +28,9 @@
The WSGI environment must contain 'zope.request'.
"""
implements(IWSGIApplication)
- adapts(IWSGIApplication, IRequest)
- def __init__(self, app, marker_request=None):
- self.app = app
+ def __init__(self, next_app):
+ self.next_app = next_app
def __call__(self, environ, start_response):
request = environ['zope.request']
@@ -48,12 +46,12 @@
newInteraction(request)
try:
- return self.app(environ, start_response)
+ return self.next_app(environ, start_response)
finally:
endInteraction()
def __repr__(self):
- return '%s(%s)' % (self.__class__.__name__, repr(self.app))
+ return '%s(%s)' % (self.__class__.__name__, repr(self.next_app))
def placeful_auth(request, ob):
Modified: Sandbox/shane/republish/zope/pipeline/apps/event.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/apps/event.py 2009-02-14 07:14:39 UTC (rev 96518)
+++ Sandbox/shane/republish/zope/pipeline/apps/event.py 2009-02-14 08:50:36 UTC (rev 96519)
@@ -13,7 +13,6 @@
##############################################################################
from zope.event import notify
-from zope.interface import adapts
from zope.interface import implements
from zope.publisher.interfaces import IWSGIApplication
from zope.publisher.interfaces.event import BeforeTraverseEvent
@@ -27,16 +26,15 @@
times.
"""
implements(IWSGIApplication)
- adapts(IWSGIApplication)
- def __init__(self, app):
- self.app = app
+ def __init__(self, next_app):
+ self.next_app = next_app
def __call__(self, environ, start_response):
request = environ['zope.request']
request.traversal_hooks.append(fireBeforeTraverse)
try:
- return self.app(environ, start_response)
+ return self.next_app(environ, start_response)
finally:
if request.traversed:
name, ob = request.traversed[-1]
Modified: Sandbox/shane/republish/zope/pipeline/apps/fixrel.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/apps/fixrel.py 2009-02-14 07:14:39 UTC (rev 96518)
+++ Sandbox/shane/republish/zope/pipeline/apps/fixrel.py 2009-02-14 08:50:36 UTC (rev 96519)
@@ -23,12 +23,11 @@
to the response text (after calling the app).
"""
implements(IWSGIApplication)
- adapts(IWSGIApplication)
allow_redirect = True
- def __init__(self, app):
- self.app = app
+ def __init__(self, next_app):
+ self.next_app = next_app
def __call__(self, environ, start_response):
request = environ['zope.request']
@@ -59,7 +58,7 @@
if not need_fix:
# No fix required
- return self.app(environ, start_response)
+ return self.next_app(environ, start_response)
if redirect:
# Redirect, then end the pipeline early
Modified: Sandbox/shane/republish/zope/pipeline/apps/openroot.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/apps/openroot.py 2009-02-14 07:14:39 UTC (rev 96518)
+++ Sandbox/shane/republish/zope/pipeline/apps/openroot.py 2009-02-14 08:50:36 UTC (rev 96519)
@@ -13,7 +13,6 @@
##############################################################################
from zope.component import getUtility
-from zope.interface import adapts
from zope.interface import implements
from zope.publisher.interfaces import IWSGIApplication
from zope.security.checker import ProxyFactory
@@ -32,13 +31,13 @@
name as the root object.
"""
implements(IWSGIApplication)
- adapts(IWSGIApplication)
root_name = 'Application'
app_controller_name = '++etc++process'
- def __init__(self, app):
- self.app = app
+ def __init__(self, next_app, database):
+ self.next_app = next_app
+ self.database = database
def __call__(self, environ, start_response):
request = environ['zope.request']
@@ -52,18 +51,15 @@
return self.app(environ, start_response)
# Open the database.
- db = environ['zope.database']
- conn = db.open()
-
- request.annotations['ZODB.interfaces.IConnection'] = conn
- root = conn.root()
- app = root.get(self.root_name, None)
- if app is None:
- raise SystemError("Zope Application Not Found")
-
- request.traversed = [(self.root_name, ProxyFactory(app))]
-
+ conn = self.database.open()
try:
- return self.app(environ, start_response)
+ request.annotations['ZODB.interfaces.IConnection'] = conn
+ root = conn.root()
+ app = root.get(self.root_name, None)
+ if app is None:
+ raise SystemError("Zope Application Not Found")
+ request.traversed = [(self.root_name, ProxyFactory(app))]
+
+ return self.next_app(environ, start_response)
finally:
conn.close()
Modified: Sandbox/shane/republish/zope/pipeline/apps/requestsetup.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/apps/requestsetup.py 2009-02-14 07:14:39 UTC (rev 96518)
+++ Sandbox/shane/republish/zope/pipeline/apps/requestsetup.py 2009-02-14 08:50:36 UTC (rev 96519)
@@ -18,7 +18,6 @@
from zope.configuration.exceptions import ConfigurationError
from zope.httpform import FormParser
from zope.i18n.interfaces import IUserPreferredCharsets
-from zope.interface import adapts
from zope.interface import implements
from zope.publisher.interfaces import IWSGIApplication
from zope.testing import cleanup
@@ -35,10 +34,9 @@
Also sets the request locale and skin.
"""
implements(IWSGIApplication)
- adapts(IWSGIApplication)
- def __init__(self, app):
- self.app = app
+ def __init__(self, next_app):
+ self.next_app = next_app
def __call__(self, environ, start_response):
scheme = environ.get('wsgi.url_scheme', 'http').lower()
@@ -51,7 +49,7 @@
self.set_locale(request)
self.set_skin(request)
- return self.app(environ, start_response)
+ return self.next_app(environ, start_response)
def set_locale(self, request):
envadapter = IUserPreferredLanguages(request, None)
@@ -88,11 +86,9 @@
is an IHTTPRequest, not just an IRequest.
"""
implements(IWSGIApplication)
- adapts(IWSGIApplication)
- request_type = IHTTPRequest
- def __init__(self, app):
- self.app = app
+ def __init__(self, next_app):
+ self.next_app = next_app
def __call__(self, environ, start_response):
request = environ['zope.request']
@@ -117,7 +113,7 @@
if parser.action:
request.traversal_stack.insert(0, parser.action)
- return self.app(environ, start_response)
+ return self.next_app(environ, start_response)
class RequestFactoryRegistry(object):
Modified: Sandbox/shane/republish/zope/pipeline/apps/retry.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/apps/retry.py 2009-02-14 07:14:39 UTC (rev 96518)
+++ Sandbox/shane/republish/zope/pipeline/apps/retry.py 2009-02-14 08:50:36 UTC (rev 96519)
@@ -12,7 +12,6 @@
#
##############################################################################
-from zope.interface import adapts
from zope.interface import implements
from zope.publisher.interfaces import IWSGIApplication
from zope.publisher.interfaces.exceptions import Retry
@@ -30,10 +29,9 @@
true.
"""
implements(IWSGIApplication)
- adapts(IWSGIApplication)
- def __init__(self, app, max_attempts=3):
- self.app = app
+ def __init__(self, next_app, max_attempts=3):
+ self.next_app = next_app
self.max_attempts = max_attempts
def __call__(self, environ, start_response):
@@ -58,7 +56,7 @@
output_file = []
environ['zope.can_retry'] = True
try:
- res = self.app(environ, retryable_start_response)
+ res = self.next_app(environ, retryable_start_response)
except (Retry, ConflictError):
if 'zope.request' in environ:
del environ['zope.request']
@@ -76,4 +74,4 @@
# try once more, this time without retry support
environ['zope.can_retry'] = False
- return self.app(environ, start_response)
+ return self.next_app(environ, start_response)
Modified: Sandbox/shane/republish/zope/pipeline/apps/switch.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/apps/switch.py 2009-02-14 07:14:39 UTC (rev 96518)
+++ Sandbox/shane/republish/zope/pipeline/apps/switch.py 2009-02-14 08:50:36 UTC (rev 96519)
@@ -14,21 +14,36 @@
from zope.interface import implements
+from zope.interface import providedBy
from zope.publisher.interfaces import IWSGIApplication
-from zope.pipeline.entry import get_pipeline
+from zope.pipeline.entry import create_pipeline
+from zope.pipeline.interfaces import IPipelineParticipant
+
class SwitchPipeline(object):
"""WSGI application that switches to a pipeline based on the request type.
+ This should be placed at the end of the INoRequest pipeline.
Requires 'zope.request' in the environment.
"""
- implements(IWSGIApplication)
+ implements(IWSGIApplication, IPipelineParticipant)
+ def __init__(self):
+ # _cache: {(interfaces provided by the request) -> pipeline}
+ self._cache = {}
+
+ def set_pipeline_params(self, name, pipeline_params):
+ self.pipeline_params = pipeline_params
+
def __call__(self, environ, start_response):
request = environ['zope.request']
- app = get_pipeline(request=request)
- return app(environ, start_response)
+ provided = tuple(providedBy(request))
+ pipeline = self._cache.get(provided)
+ if pipeline is None:
+ pipeline = create_pipeline(self.pipeline_params, provided)
+ self._cache[provided] = pipeline
+ return pipeline(environ, start_response)
def __repr__(self):
return '%s()' % self.__class__.__name__
Modified: Sandbox/shane/republish/zope/pipeline/apps/traversal.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/apps/traversal.py 2009-02-14 07:14:39 UTC (rev 96518)
+++ Sandbox/shane/republish/zope/pipeline/apps/traversal.py 2009-02-14 08:50:36 UTC (rev 96519)
@@ -12,7 +12,6 @@
#
##############################################################################
-from zope.interface import adapts
from zope.interface import implements
from zope.publisher.interfaces import IWSGIApplication
@@ -23,15 +22,14 @@
Requires 'zope.request' in the WSGI environment.
"""
implements(IWSGIApplication)
- adapts(IWSGIApplication)
- def __init__(self, app):
- self.app = app
+ def __init__(self, next_app):
+ self.next_app = next_app
def __call__(self, environ, start_response):
request = environ['zope.request']
self.traverse(request)
- return self.app(environ, start_response)
+ return self.next_app(environ, start_response)
def traverse(self, request):
traversal_stack = request.traversal_stack
@@ -63,6 +61,4 @@
class HTTPTraverser(Traverser):
implements(IWSGIApplication)
- adapts(IWSGIApplication)
- request_type = IHTTPRequest
Modified: Sandbox/shane/republish/zope/pipeline/apps/txnctl.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/apps/txnctl.py 2009-02-14 07:14:39 UTC (rev 96518)
+++ Sandbox/shane/republish/zope/pipeline/apps/txnctl.py 2009-02-14 08:50:36 UTC (rev 96519)
@@ -15,7 +15,6 @@
import transaction
from zope.location.interfaces import ILocationInfo
-from zope.interface import adapts
from zope.interface import implements
from zope.interface import providedBy
from zope.publisher.interfaces import IRequest
@@ -27,15 +26,14 @@
"""WSGI middleware that begins and commits/aborts transactions.
"""
implements(IWSGIApplication)
- adapts(IWSGIApplication)
- def __init__(self, app):
- self.app = app
+ def __init__(self, next_app):
+ self.next_app = next_app
def __call__(self, environ, start_response):
transaction.begin()
try:
- res = self.app(environ, start_response)
+ res = self.next_app(environ, start_response)
except:
transaction.abort()
raise
@@ -53,10 +51,9 @@
Requires 'zope.request' in the environment.
"""
implements(IWSGIApplication)
- adapts(IWSGIApplication)
- def __init__(self, app):
- self.app = app
+ def __init__(self, next_app):
+ self.next_app = next_app
def __call__(self, environ, start_response):
res = self.app(environ, start_response)
Modified: Sandbox/shane/republish/zope/pipeline/configure.zcml
===================================================================
--- Sandbox/shane/republish/zope/pipeline/configure.zcml 2009-02-14 07:14:39 UTC (rev 96518)
+++ Sandbox/shane/republish/zope/pipeline/configure.zcml 2009-02-14 08:50:36 UTC (rev 96519)
@@ -1,12 +1,12 @@
<configure xmlns="http://namespaces.zope.org/zope"
xmlns:wsgi="http://namespaces.zope.org/wsgi">
-<!-- a wsgi:pipeline directive specifies the names of
+<!-- A wsgi:pipeline directive specifies the names of
applications to use in a pipeline. Its implementation
registers a bound PipelineApplicationList.adapt() method as an
unnamed adapter from the request type to IPipelineApplicationList. -->
-<wsgi:pipeline for=".interfaces.IUndecidedRequest" names="
+<wsgi:pipeline for=".interfaces.INoRequest" names="
virtual_host
retry
create_request
@@ -27,85 +27,80 @@
call
" />
-<!-- a wsgi:middleware directive registers an application for use
- as middleware in a pipeline. It is like an adapter directive,
- except that the adapter is registered as requiring
- two parameters, 'app' and 'request', while only the 'app' parameter is
- provided to the middleware factory; the factory is wrapped
- to make that happen. If neither the directive nor the factory
+<!-- A wsgi:application directive registers an application for use
+ as an application in a pipeline. If the application is the last
+ element of the pipeline, the factory will be passed no positional
+ parameters. Otherwise, the application will be passed the next
+ application in the pipeline as the only positional parameter.
+
+ The implementation of this directive registers a new
+ WSGIApplicationFactory as an adapter from a marker request to
+ IWSGIApplicationFactory. If neither the directive nor the factory
says what kind of request is required, assume IRequest. -->
-<wsgi:middleware
- factory=".apps.retry.Retry"
+<wsgi:application
name="retry"
+ factory=".apps.retry.Retry"
for=".interfaces.INoRequest" />
-<wsgi:middleware
- factory=".apps.requestsetup.CreateRequest"
+<wsgi:application
name="create_request"
+ factory=".apps.requestsetup.CreateRequest"
for=".interfaces.INoRequest" />
-<!-- a wsgi:application directive registers an application for use
- as the final application in a pipeline. It is like an adapter
- directive, except that the adapter is registered as requiring
- one parameter, 'request', while no parameters are passed to the
- application factory; the factory is wrapped
- to make that happen. If neither the directive nor the factory
- says what kind of request is required, assume IRequest. -->
-
<wsgi:application
- factory=".apps.switch.SwitchPipeline"
name="switch_pipeline"
+ factory=".apps.switch.SwitchPipeline"
for=".interfaces.INoRequest" />
-<wsgi:middleware
- factory="..."
- name="log" />
+<wsgi:application
+ name="log"
+ factory="..." />
-<wsgi:middleware
- factory=".apps.openroot.RootOpener"
- name="open_root" />
+<wsgi:application
+ name="open_root"
+ factory=".apps.openroot.RootOpener" />
-<wsgi:middleware
- factory=".apps.txnctl.TransactionController"
- name="control_transaction" />
+<wsgi:application
+ name="control_transaction"
+ factory=".apps.txnctl.TransactionController" />
-<wsgi:middleware
- factory=".apps.notify.EventNotifier"
- name="event" />
+<wsgi:application
+ name="event"
+ factory=".apps.notify.EventNotifier" />
-<wsgi:middleware
- factory="..."
- name="handle_error" />
+<wsgi:application
+ name="handle_error"
+ factory="..." />
<!-- no form processing for non-browser requests -->
-<wsgi:middleware
- factory=".apps.passthrough"
+<wsgi:application
name="process_form"
+ factory=".apps.passthrough"
for="zope.publisher.interfaces.IRequest" />
<!-- process forms for browser requests -->
-<wsgi:middleware
- factory=".apps.requestsetup.ProcessForm"
+<wsgi:application
name="process_form"
+ factory=".apps.requestsetup.ProcessForm"
for="zope.publisher.interfaces.browser.IBrowserRequest" />
-<wsgi:middleware
- factory=".apps.authenticate.Authenticator"
- name="authenticate" />
+<wsgi:application
+ name="authenticate"
+ factory=".apps.authenticate.Authenticator" />
-<wsgi:middleware
- factory=".apps.traversal.Traverser"
- name="traverse" />
+<wsgi:application
+ name="traverse"
+ factory=".apps.traversal.Traverser" />
-<wsgi:middleware
- factory=".apps.txnctl.TransactionAnnotator"
- name="annotate_transaction" />
+<wsgi:application
+ name="annotate_transaction"
+ factory=".apps.txnctl.TransactionAnnotator" />
<wsgi:application
- factory=".apps.mapply.Caller"
- name="call" />
+ name="call"
+ factory=".apps.mapply.Caller" />
</configure>
Modified: Sandbox/shane/republish/zope/pipeline/entry.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/entry.py 2009-02-14 07:14:39 UTC (rev 96518)
+++ Sandbox/shane/republish/zope/pipeline/entry.py 2009-02-14 08:50:36 UTC (rev 96519)
@@ -12,72 +12,42 @@
#
##############################################################################
"""The main entry point for the zope.pipeline package.
-
-Use get_database_pipeline() or get_pipeline() to get a WSGI
-application built from a pipeline.
"""
-from zope.component import getMultiAdapter
from zope.interface import directlyProvides
-from zope.interface import providedBy
+from zope.pipeline.interfaces import INoRequest
from zope.pipeline.interfaces import IPipelineApplicationList
-from zope.pipeline.interfaces import IUndecidedRequest
-from zope.publisher import IWSGIApplication
-from zope.testing import cleanup
+from zope.pipeline.interfaces import IPipelineParticipant
+from zope.pipeline.interfaces import IWSGIApplicationFactory
-# _pipeline_cache: {(interfaces provided by the request) -> WSGI application}
-_pipeline_cache = {}
-cleanup.addCleanUp(_pipeline_cache.clear)
-def get_database_pipeline(database, global_environ=None):
- """Get a pipeline that will connect to the given database.
+def create_pipeline(params, request_provides=None):
+ """Return a pipeline as a WSGI application.
- The returned pipeline can be used for many requests, even
- concurrently.
- """
- d = {}
- if global_environ is not None:
- d.update(global_environ)
- d['zope.database'] = database
- return get_pipeline(global_environ=global_environ)
+ The `params` contains a mapping of application name to
+ factory keyword parameter map. An example `params` would be
+ ``{'open_root': {'database': zodb_db_object}}``.
-def get_pipeline(request=None, global_environ=None):
- """Get a pipeline.
-
- The returned pipeline can be used for many requests, even
- concurrently.
+ The `request_provides` parameter varies the pipeline according
+ to the type of the `zope.request` in the WSGI environment.
+ If the WSGI environment to process has no `zope.request`, the
+ `request.provides` parameter should be None (the default).
"""
- if request is None:
- provided = (IUndecidedRequest,)
- else:
- provided = tuple(providedBy(request))
- pipeline = _pipeline_cache.get(provided)
- if pipeline is None:
- pipeline = make_pipeline(provided, global_environ)
- _pipeline_cache[provided] = pipeline
- return pipeline
+ if request_provides is None:
+ request_provides = (INoRequest,)
+ marker_request = MarkerRequest(request_provides)
+ app_list = IPipelineApplicationList(marker_request)
+ app = None
+ for name in reversed(app_list.names):
+ factory = IWSGIApplicationFactory(marker_request, name=name)
+ app = factory.create(name, params, app)
+ # If the app or some adapter needs to know the parameters
+ # for the whole pipeline, tell it.
+ participant = IPipelineParticipant(app, None)
+ if participant is not None:
+ participant.set_pipeline_params(app_name, params)
+ return app
-def make_pipeline(provided, global_environ=None):
- marker_req = MarkerRequest(provided)
- app_list = IPipelineApplicationList(marker_req)
- names = list(app_list.names) # make a copy
- # The last name in the list is an application.
- name = names.pop()
- app = IWSGIApplication(marker_req, name=name)
- while names:
- # The rest of the names are middleware.
- name = names.pop()
- app = getMultiAdapter(
- (app, marker_req), IWSGIApplication, name=name)
- if global_environ:
- # augment the WSGI environment with some data
- def add_global_environ(environ, start_response):
- environ.update(global_environ)
- return inner_app(environ, start_response)
- directlyProvides(add_global_environ, IWSGIApplication)
- return add_global_environ
- else:
- return app
class MarkerRequest(object):
"""A marker object that claims to provide a request type.
Modified: Sandbox/shane/republish/zope/pipeline/interfaces.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/interfaces.py 2009-02-14 07:14:39 UTC (rev 96518)
+++ Sandbox/shane/republish/zope/pipeline/interfaces.py 2009-02-14 08:50:36 UTC (rev 96519)
@@ -19,8 +19,8 @@
from zope.interface import Attribute
from zope.interface import Interface
-class IUndecidedRequest(Interface):
- """Indicates that no request has been created yet.
+class INoRequest(Interface):
+ """Indicates that no Zope request has been created yet.
Use this interface to register WSGI applications in the
pipeline that executes before the request creation step.
@@ -34,6 +34,32 @@
"""
names = Attribute("Application names to use in a pipeline")
+class IWSGIApplicationFactory(Interface):
+ """Creates a WSGI application.
+
+ The two-step WSGI application creation process makes it
+ possible to pass parameters to the application constructor.
+ """
+ def create(app_name, pipeline_params, next_app=None):
+ """Create and return the application.
+
+ name is the name assigned to the application in this pipeline.
+
+ pipeline_params is a mapping of application name to parameter map.
+ In other words: {app_name: {param_name: param_value}}.
+
+ 'next_app' is the next WSGI application in the pipeline. It is
+ None when the application is the last in the pipeline.
+ """
+
+class IPipelineParticipant(Interface):
+ """Provides info for a WSGI app that needs to know about its pipeline.
+ """
+ def set_pipeline_params(app_name, pipeline_params):
+ """Tells the app about its name in the pipeline and all parameters.
+ """
+
+
class IRequestFactoryRegistry(Interface):
"""A registry of request factories.
Modified: Sandbox/shane/republish/zope/pipeline/meta.zcml
===================================================================
--- Sandbox/shane/republish/zope/pipeline/meta.zcml 2009-02-14 07:14:39 UTC (rev 96518)
+++ Sandbox/shane/republish/zope/pipeline/meta.zcml 2009-02-14 08:50:36 UTC (rev 96519)
@@ -16,13 +16,6 @@
<meta:directive
namespace="http://namespaces.zope.org/wsgi"
- name="middleware"
- schema=".zcml.IMiddlewareDirective"
- handler=".zcml.middleware"
- />
-
-<meta:directive
- namespace="http://namespaces.zope.org/wsgi"
name="request-factory"
schema=".zcml.IRequestFactoryDirective"
handler=".zcml.request_factory"
Modified: Sandbox/shane/republish/zope/pipeline/zcml.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/zcml.py 2009-02-14 07:14:39 UTC (rev 96518)
+++ Sandbox/shane/republish/zope/pipeline/zcml.py 2009-02-14 08:50:36 UTC (rev 96519)
@@ -31,6 +31,7 @@
from zope.schema import TextLine
from zope.pipeline.interfaces import IPipelineApplicationList
+from zope.pipeline.interfaces import IWSGIApplicationFactory
from zope.pipeline.apps.requestsetup import factoryRegistry
@@ -40,98 +41,92 @@
for_ = Tokens(
title=u'Request types',
description=u'The request types that should use this pipeline',
- value_type=GlobalObject(),
- required=True)
+ value_type=GlobalObject())
names = Tokens(
title=u'Application names',
- description=u'The list of WSGI application names to use. '
- 'The last name in the list declares a simple application; '
- 'the rest declare a middleware application.',
- required=True)
+ description=(
+ u'The list of WSGI application names to use. '
+ u'The last name in the list declares a simple application; '
+ u'the rest declare a middleware application.'))
+class PipelineApplicationList(object):
+ implements(IPipelineApplicationList)
-class IApplicationDirective(Interface):
- """Declare a simple WSGI application for use at the end of a pipeline"""
+ def __init__(self, names):
+ self.names = names
- factory = GlobalObject(
- title=u"Application factory",
- description=(u"A factory that creates the WSGI application. "
- u"The factory will be called with no parameters."),
- required=True,
- )
+ def adapt(self, marker_request):
+ """Called by adapter lookup"""
+ return self
+def pipeline(_context, for_, names):
+ """Register a pipeline application list"""
+ obj = PipelineApplicationList(names)
+ adapter(_context, factory=obj.adapt,
+ provides=[IPipelineApplicationList], for_=for_)
+
+
+
+class IApplicationDirective(Interface):
+ """Declare a WSGI application."""
+
name = TextLine(
title=u"Name",
- description=u"The name of the application",
- required=True,
- )
+ description=u"The name of the application")
+ factory = GlobalObject(
+ title=u"Application factory",
+ description=(
+ u"A factory that creates the WSGI application. "
+ u"If the application is used in the pipeline as "
+ u"middleware, the factory will be passed a single "
+ u"positional parameter containing the next "
+ u"application in the pipeline. Other parameters "
+ u"specified for the pipeline may also be passed as "
+ u"keyword parameters."))
+
for_ = Tokens(
title=u'Request types',
description=u'The request types that should use this application',
value_type=GlobalObject(),
required=False)
+class WSGIApplicationFactory(object):
+ implements(IWSGIApplicationFactory)
-class IMiddlewareDirective(IApplicationDirective):
- """Declare a middleware WSGI application for use in a pipeline"""
- factory = GlobalObject(
- title=u"Application factory",
- description=(u"A factory that creates the WSGI application. "
- u"The factory will be called with one parameter: "
- u"the next application in the pipeline."),
- required=True,
- )
+ def __init__(self, app_factory):
+ self.app_factory = app_factory
-
-class PipelineApplicationList(object):
- implements(IPipelineApplicationList)
-
- def __init__(self, names):
- self.names = names
-
- def adapt(self, request):
+ def adapt(self, marker_request):
"""Called by adapter lookup"""
return self
+ def create(self, app_name, pipeline_params, next_app=None):
+ kw = pipeline_params.get(app_name)
+ if kw is None:
+ kw = {}
+ if next_app is not None:
+ # middleware
+ app = self.app_factory(next_app, **kw)
+ else:
+ # final app
+ app = self.app_factory(**kw)
+ return app
-def pipeline(_context, for_, names):
- """Register a pipeline application list"""
- obj = PipelineApplicationList(names)
- adapter(_context, factory=obj.adapt,
- provides=[IPipelineApplicationList], for_=for_)
-
def application(_context, factory, name, for_=()):
- """Register a simple WSGI app for use at the end of pipeline"""
+ """Register a WSGI application"""
if not for_:
- for_ = [getattr(factory, 'request_type', IRequest)]
-
- def app_factory(marker_request):
- res = factory()
- if not IWSGIApplication.providedBy(res):
- alsoProvides(res, IWSGIApplication)
- return res
-
- adapter(_context, factory=[app_factory], provides=[IWSGIApplication],
+ for_ = [IRequest]
+ factory_factory = WSGIApplicationFactory(factory)
+ adapter(_context,
+ factory=[factory_factory.adapt],
+ provides=[IWSGIApplicationFactory],
for_=for_, name=name)
-def middleware(_context, factory, name, for_=()):
- """Register a middleware WSGI app for use in a pipeline"""
- if not for_:
- for_ = [getattr(factory, 'request_type', IRequest)]
- for_ = [IWSGIApplication] + list(for_)
- def app_factory(app, marker_request):
- res = factory(app)
- if not IWSGIApplication.providedBy(res):
- alsoProvides(res, IWSGIApplication)
- return res
- adapter(_context, factory=[app_factory], provides=[IWSGIApplication],
- for_=for_, name=name)
-
class IRequestFactoryDirective(Interface):
"""Link information from a request to a request factory"""
More information about the Checkins
mailing list