[Checkins] SVN: Sandbox/shane/republish/zope/pipeline/ Reorganized code and added copyright notices
Shane Hathaway
shane at hathawaymix.org
Thu Feb 12 00:25:08 EST 2009
Log message for revision 96459:
Reorganized code and added copyright notices
Changed:
A Sandbox/shane/republish/zope/pipeline/apps/
A Sandbox/shane/republish/zope/pipeline/apps/__init__.py
A Sandbox/shane/republish/zope/pipeline/apps/authenticator.py
A Sandbox/shane/republish/zope/pipeline/apps/caller.py
A Sandbox/shane/republish/zope/pipeline/apps/errorhandler.py
A Sandbox/shane/republish/zope/pipeline/apps/notify.py
A Sandbox/shane/republish/zope/pipeline/apps/passthrough.py
A Sandbox/shane/republish/zope/pipeline/apps/requestfactory.py
A Sandbox/shane/republish/zope/pipeline/apps/retry.py
A Sandbox/shane/republish/zope/pipeline/apps/rootopen.py
A Sandbox/shane/republish/zope/pipeline/apps/switch.py
A Sandbox/shane/republish/zope/pipeline/apps/traverser.py
A Sandbox/shane/republish/zope/pipeline/apps/txnctl.py
D Sandbox/shane/republish/zope/pipeline/authenticator.py
U Sandbox/shane/republish/zope/pipeline/autotemp.py
D Sandbox/shane/republish/zope/pipeline/build.py
D Sandbox/shane/republish/zope/pipeline/caller.py
D Sandbox/shane/republish/zope/pipeline/complextraverser.py
U Sandbox/shane/republish/zope/pipeline/configure.zcml
D Sandbox/shane/republish/zope/pipeline/errorhandler.py
D Sandbox/shane/republish/zope/pipeline/event.py
U Sandbox/shane/republish/zope/pipeline/meta.zcml
D Sandbox/shane/republish/zope/pipeline/passthrough.py
D Sandbox/shane/republish/zope/pipeline/requestcreator.py
D Sandbox/shane/republish/zope/pipeline/retry.py
D Sandbox/shane/republish/zope/pipeline/rootopen.py
D Sandbox/shane/republish/zope/pipeline/simpletraverser.py
D Sandbox/shane/republish/zope/pipeline/switch.py
D Sandbox/shane/republish/zope/pipeline/traverser.py
D Sandbox/shane/republish/zope/pipeline/txnctl.py
U Sandbox/shane/republish/zope/pipeline/zcml.py
-=-
Property changes on: Sandbox/shane/republish/zope/pipeline/apps
___________________________________________________________________
Added: svn:mergeinfo
+
Added: Sandbox/shane/republish/zope/pipeline/apps/__init__.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/apps/__init__.py (rev 0)
+++ Sandbox/shane/republish/zope/pipeline/apps/__init__.py 2009-02-12 05:25:08 UTC (rev 96459)
@@ -0,0 +1 @@
+"""Various WSGI applications and middleware used in a standard Zope pipeline"""
Copied: Sandbox/shane/republish/zope/pipeline/apps/authenticator.py (from rev 96440, Sandbox/shane/republish/zope/pipeline/authenticator.py)
===================================================================
--- Sandbox/shane/republish/zope/pipeline/apps/authenticator.py (rev 0)
+++ Sandbox/shane/republish/zope/pipeline/apps/authenticator.py 2009-02-12 05:25:08 UTC (rev 96459)
@@ -0,0 +1,86 @@
+##############################################################################
+#
+# Copyright (c) 2009 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.
+#
+##############################################################################
+
+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
+from zope.security.management import endInteraction
+
+from zope.app.security.interfaces import IAuthentication
+from zope.app.security.interfaces import IFallbackUnauthenticatedPrincipal
+
+
+class Authenticator(object):
+ """WSGI app that hooks into Zope-based authentication.
+
+ The WSGI environment must contain 'zope.request'.
+ """
+ implements(IWSGIApplication)
+ adapts(IWSGIApplication, IRequest)
+
+ def __init__(self, app, marker_request=None):
+ self.app = app
+
+ def __call__(self, environ, start_response):
+ request = environ['zope.request']
+ auth = getGlobalSiteManager().getUtility(IAuthentication)
+ principal = auth.authenticate(request)
+ if principal is None:
+ request.traversal_hooks.append(placeful_auth)
+ principal = auth.unauthenticatedPrincipal()
+ if principal is None:
+ # Get the fallback unauthenticated principal
+ principal = getUtility(IFallbackUnauthenticatedPrincipal)
+ request.principal = principal
+
+ newInteraction(request)
+ try:
+ return self.app(environ, start_response)
+ finally:
+ endInteraction()
+
+ def __repr__(self):
+ return '%s(%s)' % (self.__class__.__name__, repr(self.app))
+
+
+def placeful_auth(request, ob):
+ """Traversal hook that tries to authenticate in a context"""
+
+ if not IUnauthenticatedPrincipal.providedBy(request.principal):
+ # We've already got an authenticated user. There's nothing to do.
+ # Note that beforeTraversal guarentees that user is not None.
+ return
+
+ if not ISite.providedBy(ob):
+ # We won't find an authentication utility here, so give up.
+ return
+
+ sm = removeSecurityProxy(ob).getSiteManager()
+
+ auth = sm.queryUtility(IAuthentication)
+ if auth is None:
+ # No auth utility here
+ return
+
+ # Try to authenticate against the auth utility
+ principal = auth.authenticate(request)
+ if principal is None:
+ principal = auth.unauthenticatedPrincipal()
+ if principal is None:
+ # nothing to do here
+ return
+
+ request.setPrincipal(principal)
Property changes on: Sandbox/shane/republish/zope/pipeline/apps/authenticator.py
___________________________________________________________________
Added: svn:mergeinfo
+
Copied: Sandbox/shane/republish/zope/pipeline/apps/caller.py (from rev 96450, Sandbox/shane/republish/zope/pipeline/caller.py)
===================================================================
--- Sandbox/shane/republish/zope/pipeline/apps/caller.py (rev 0)
+++ Sandbox/shane/republish/zope/pipeline/apps/caller.py 2009-02-12 05:25:08 UTC (rev 96459)
@@ -0,0 +1,131 @@
+##############################################################################
+#
+# Copyright (c) 2009 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.
+#
+##############################################################################
+
+from zope.interface import implements
+from zope.proxy import removeAllProxies
+from zope.publisher.interfaces import IWSGIApplication
+
+
+class Caller(object):
+ """WSGI app that calls the traversed object.
+
+ Requires 'zope.request', which implements IRequest, in the environment.
+ The 'traversed' attribute of the request must be set.
+ """
+ implements(IWSGIApplication)
+
+ def __call__(self, environ, start_response):
+ request = environ['zope.request']
+ name, ob = request.traversed[-1]
+ result = mapply(ob, request.positional_arguments, request)
+ response = request.response
+ if result is not response:
+ response.setResult(result)
+ start_response(response.getStatusString(), response.getHeaders())
+ return response.consumeBodyIter()
+
+ def __repr__(self):
+ return '%s()' % self.__class__.__name__
+
+
+_marker = object() # Create a new marker object.
+
+def unwrapMethod(obj):
+ """obj -> (unwrapped, wrapperCount)
+
+ Unwrap 'obj' until we get to a real function, counting the number of
+ unwrappings.
+
+ Bail if we find a class or something we can't identify as callable.
+ """
+ wrapperCount = 0
+ unwrapped = obj
+
+ for i in range(10):
+ bases = getattr(unwrapped, '__bases__', None)
+ if bases is not None:
+ raise TypeError("mapply() can not call class constructors")
+
+ im_func = getattr(unwrapped, 'im_func', None)
+ if im_func is not None:
+ unwrapped = im_func
+ wrapperCount += 1
+ elif getattr(unwrapped, 'func_code', None) is not None:
+ break
+ else:
+ unwrapped = getattr(unwrapped, '__call__' , None)
+ if unwrapped is None:
+ raise TypeError("mapply() can not call %s" % repr(obj))
+ else:
+ raise TypeError("couldn't find callable metadata, mapply() error on %s"
+ % repr(obj))
+
+ return unwrapped, wrapperCount
+
+
+def mapply(obj, positional=(), request={}):
+ __traceback_info__ = obj
+
+ # we need deep access for introspection. Waaa.
+ unwrapped = removeAllProxies(obj)
+
+ unwrapped, wrapperCount = unwrapMethod(unwrapped)
+
+ code = unwrapped.func_code
+ defaults = unwrapped.func_defaults
+ names = code.co_varnames[wrapperCount:code.co_argcount]
+
+ nargs = len(names)
+ if not positional:
+ args = []
+ else:
+ args = list(positional)
+ if len(args) > nargs:
+ given = len(args)
+ if wrapperCount:
+ given += wrapperCount
+ raise TypeError('%s() takes at most %d argument%s(%d given)' % (
+ getattr(unwrapped, '__name__', repr(obj)),
+ code.co_argcount,
+ (code.co_argcount > 1 and 's ' or ' '),
+ given))
+
+ get = request.get
+ nrequired = len(names)
+ if defaults:
+ nrequired -= len(defaults)
+
+ for index in range(len(args), nargs):
+ name = names[index]
+ v = get(name, _marker)
+ if v is _marker:
+ if name == 'REQUEST':
+ v = request
+ elif index < nrequired:
+ raise TypeError('Missing argument to %s(): %s' % (
+ getattr(unwrapped, '__name__', repr(obj)), name))
+ else:
+ v = defaults[index - nrequired]
+ args.append(v)
+
+ args = tuple(args)
+
+ if __debug__:
+ return debug_call(obj, args)
+
+ return obj(*args)
+
+def debug_call(obj, args):
+ # The presence of this function allows us to set a pdb breakpoint
+ return obj(*args)
Copied: Sandbox/shane/republish/zope/pipeline/apps/notify.py (from rev 96435, Sandbox/shane/republish/zope/pipeline/event.py)
===================================================================
--- Sandbox/shane/republish/zope/pipeline/apps/notify.py (rev 0)
+++ Sandbox/shane/republish/zope/pipeline/apps/notify.py 2009-02-12 05:25:08 UTC (rev 96459)
@@ -0,0 +1,48 @@
+##############################################################################
+#
+# Copyright (c) 2009 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.
+#
+##############################################################################
+
+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
+from zope.publisher.interfaces.event import EndRequestEvent
+
+
+class EventNotifier(object):
+ """Fires request-related events.
+
+ Fires are BeforeTraverseEvent and EndRequestEvent at the appropriate
+ times.
+ """
+ implements(IWSGIApplication)
+ adapts(IWSGIApplication)
+
+ def __init__(self, app):
+ self.app = app
+
+ def __call__(self, environ, start_response):
+ request = environ['zope.request']
+ request.traversal_hooks.append(fireBeforeTraverse)
+ try:
+ return self.app(environ, start_response)
+ finally:
+ if request.traversed:
+ name, ob = request.traversed[-1]
+ else:
+ ob = None
+ notify(EndRequestEvent(ob, request))
+
+def fireBeforeTraverse(request, ob):
+ notify(BeforeTraverseEvent(ob, request))
Property changes on: Sandbox/shane/republish/zope/pipeline/apps/notify.py
___________________________________________________________________
Added: svn:mergeinfo
+
Copied: Sandbox/shane/republish/zope/pipeline/apps/passthrough.py (from rev 96451, Sandbox/shane/republish/zope/pipeline/passthrough.py)
===================================================================
--- Sandbox/shane/republish/zope/pipeline/apps/passthrough.py (rev 0)
+++ Sandbox/shane/republish/zope/pipeline/apps/passthrough.py 2009-02-12 05:25:08 UTC (rev 96459)
@@ -0,0 +1,23 @@
+##############################################################################
+#
+# Copyright (c) 2009 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.
+#
+##############################################################################
+
+
+def passthrough(app):
+ """A passthrough application.
+
+ Use this to skip a pipeline step. Register this function
+ as the middleware factory for a step you don't want to use.
+ The step will be eliminated even from application stack traces.
+ """
+ return app
Property changes on: Sandbox/shane/republish/zope/pipeline/apps/passthrough.py
___________________________________________________________________
Added: svn:mergeinfo
+
Copied: Sandbox/shane/republish/zope/pipeline/apps/retry.py (from rev 96435, Sandbox/shane/republish/zope/pipeline/retry.py)
===================================================================
--- Sandbox/shane/republish/zope/pipeline/apps/retry.py (rev 0)
+++ Sandbox/shane/republish/zope/pipeline/apps/retry.py 2009-02-12 05:25:08 UTC (rev 96459)
@@ -0,0 +1,79 @@
+##############################################################################
+#
+# Copyright (c) 2009 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.
+#
+##############################################################################
+
+from zope.interface import adapts
+from zope.interface import implements
+from zope.publisher.interfaces import IWSGIApplication
+from zope.publisher.interfaces.exceptions import Retry
+from ZODB.POSException import ConflictError
+
+from zope.pipeline.autotemp import AutoTemporaryFile
+
+
+class Retry(object):
+ """Retries requests when a Retry or ConflictError propagates.
+
+ This middleware app should enclose the app that creates zope.request.
+ It sets an environment variable named 'zope.can_retry'. Error handlers
+ should propagate Retry or ConflictError when 'zope.can_retry' is
+ true.
+ """
+ implements(IWSGIApplication)
+ adapts(IWSGIApplication)
+
+ def __init__(self, app, max_attempts=3):
+ self.app = app
+ self.max_attempts = max_attempts
+
+ def __call__(self, environ, start_response):
+ wsgi_input = environ.get('wsgi.input')
+ if wsgi_input is not None:
+ if not hasattr(wsgi_input, 'seek'):
+ # make the input stream rewindable
+ f = AutoTemporaryFile()
+ f.copyfrom(wsgi_input)
+ f.seek(0)
+ environ['wsgi.input'] = wsgi_input = f
+
+ def retryable_start_response(status, response_headers, exc_info=None):
+ start_response_params[:] = [status, response_headers, exc_info]
+ tmp = AutoTemporaryFile()
+ output_file[:] = [tmp]
+ return tmp
+
+ attempt = 1
+ while attempt < self.max_attempts:
+ start_response_params = []
+ output_file = []
+ environ['zope.can_retry'] = True
+ try:
+ res = self.app(environ, retryable_start_response)
+ except (Retry, ConflictError):
+ if 'zope.request' in environ:
+ del environ['zope.request']
+ if wsgi_input is not None:
+ wsgi_input.seek(0)
+ attempt += 1
+ else:
+ if start_response_params:
+ dest = start_response(*tuple(start_response_params))
+ src = output_file[0]
+ src.seek(0)
+ src.copyto(dest)
+ src.close()
+ return res
+
+ # try once more, this time without retry support
+ environ['zope.can_retry'] = False
+ return self.app(environ, start_response)
Property changes on: Sandbox/shane/republish/zope/pipeline/apps/retry.py
___________________________________________________________________
Added: svn:mergeinfo
+
Copied: Sandbox/shane/republish/zope/pipeline/apps/rootopen.py (from rev 96435, Sandbox/shane/republish/zope/pipeline/rootopen.py)
===================================================================
--- Sandbox/shane/republish/zope/pipeline/apps/rootopen.py (rev 0)
+++ Sandbox/shane/republish/zope/pipeline/apps/rootopen.py 2009-02-12 05:25:08 UTC (rev 96459)
@@ -0,0 +1,68 @@
+##############################################################################
+#
+# Copyright (c) 2009 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.
+#
+##############################################################################
+
+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
+
+
+class RootOpener(object):
+ """Puts a root object in 'zope.request' of the WSGI environment.
+
+ Sets request.traversed to a list with one element.
+ Also closes the database connection on the way out.
+
+ Special case: if the traversal stack contains "++etc++process",
+ instead of opening the database, this uses the utility by that
+ name as the root object.
+ """
+ implements(IWSGIApplication)
+ adapts(IWSGIApplication, IZopeConfiguration)
+
+ database_name = 'main'
+ root_name = 'Application'
+ app_controller_name = '++etc++process'
+
+ def __init__(self, app, zope_conf):
+ self.app = app
+ self.db = zope_conf.databases[self.database_name]
+
+ def __call__(self, environ, start_response):
+ request = environ['zope.request']
+
+ # If the traversal stack contains self.app_controller_name,
+ # then we should get the app controller rather than look
+ # in the database.
+ if self.app_controller_name in request.traversal_stack:
+ root = getUtility(name=self.app_controller_name)
+ request.traversed = [(self.app_controller_name, root)]
+ return self.app(environ, start_response)
+
+ # Open the database.
+ conn = self.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))]
+
+ try:
+ return self.app(environ, start_response)
+ finally:
+ conn.close()
Copied: Sandbox/shane/republish/zope/pipeline/apps/switch.py (from rev 96451, Sandbox/shane/republish/zope/pipeline/switch.py)
===================================================================
--- Sandbox/shane/republish/zope/pipeline/apps/switch.py (rev 0)
+++ Sandbox/shane/republish/zope/pipeline/apps/switch.py 2009-02-12 05:25:08 UTC (rev 96459)
@@ -0,0 +1,32 @@
+##############################################################################
+#
+# Copyright (c) 2009 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.
+#
+##############################################################################
+
+
+from zope.interface import implements
+from zope.publisher.interfaces import IWSGIApplication
+
+class SwitchPipeline(object):
+ """WSGI application that switches to a pipeline based on the request type.
+
+ Requires 'zope.request' in the environment.
+ """
+ implements(IWSGIApplication)
+
+ def __call__(self, environ, start_response):
+ request = environ['zope.request']
+ app = IWSGIApplication(request, name='pipeline')
+ return app(environ, start_response)
+
+ def __repr__(self):
+ return '%s()' % self.__class__.__name__
Property changes on: Sandbox/shane/republish/zope/pipeline/apps/switch.py
___________________________________________________________________
Added: svn:mergeinfo
+
Copied: Sandbox/shane/republish/zope/pipeline/apps/traverser.py (from rev 96440, Sandbox/shane/republish/zope/pipeline/traverser.py)
===================================================================
--- Sandbox/shane/republish/zope/pipeline/apps/traverser.py (rev 0)
+++ Sandbox/shane/republish/zope/pipeline/apps/traverser.py 2009-02-12 05:25:08 UTC (rev 96459)
@@ -0,0 +1,68 @@
+##############################################################################
+#
+# Copyright (c) 2009 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.
+#
+##############################################################################
+
+from zope.interface import adapts
+from zope.interface import implements
+from zope.publisher.interfaces import IWSGIApplication
+
+
+class Traverser(object):
+ """Traverses the object graph based on the traversal stack.
+
+ Requires 'zope.request' in the WSGI environment.
+ """
+ implements(IWSGIApplication)
+ adapts(IWSGIApplication)
+
+ def __init__(self, app):
+ self.app = app
+
+ def __call__(self, environ, start_response):
+ request = environ['zope.request']
+ self.traverse(request)
+ return self.app(environ, start_response)
+
+ def traverse(self, request):
+ traversal_stack = request.traversal_stack
+ traversal_hooks = request.traversal_hooks
+ traversed = request.traversed
+
+ root_name, obj = traversed[-1]
+ prev_object = None
+
+ while True:
+ if obj is not prev_object:
+ # Call hooks (but not more than once).
+ for hook in traversal_hooks:
+ hook(request, obj)
+
+ if not traversal_stack:
+ break
+
+ prev_object = obj
+
+ # Traverse to the next step.
+ name = traversal_stack.pop()
+ obj = self.traverse_name(obj, name)
+ traversed.append((name, obj))
+
+ def traverse_name(self, obj, name):
+ pass
+
+
+class HTTPTraverser(Traverser):
+ implements(IWSGIApplication)
+ adapts(IWSGIApplication)
+ request_type = IHTTPRequest
+
Property changes on: Sandbox/shane/republish/zope/pipeline/apps/traverser.py
___________________________________________________________________
Added: svn:mergeinfo
+
Copied: Sandbox/shane/republish/zope/pipeline/apps/txnctl.py (from rev 96450, Sandbox/shane/republish/zope/pipeline/txnctl.py)
===================================================================
--- Sandbox/shane/republish/zope/pipeline/apps/txnctl.py (rev 0)
+++ Sandbox/shane/republish/zope/pipeline/apps/txnctl.py 2009-02-12 05:25:08 UTC (rev 96459)
@@ -0,0 +1,105 @@
+##############################################################################
+#
+# Copyright (c) 2009 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 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
+from zope.publisher.interfaces import IWSGIApplication
+from zope.security.proxy import removeSecurityProxy
+
+
+class TransactionController(object):
+ """WSGI middleware that begins and commits/aborts transactions.
+ """
+ implements(IWSGIApplication)
+ adapts(IWSGIApplication)
+
+ def __init__(self, app):
+ self.app = app
+
+ def __call__(self, environ, start_response):
+ transaction.begin()
+ try:
+ res = self.app(environ, start_response)
+ except:
+ transaction.abort()
+ raise
+ txn = transaction.get()
+ if txn.isDoomed():
+ txn.abort()
+ else:
+ txn.commit()
+ return res
+
+
+class TransactionAnnotator(object):
+ """WSGI middleware that annotates transactions.
+
+ Requires 'zope.request' in the environment.
+ """
+ implements(IWSGIApplication)
+ adapts(IWSGIApplication)
+
+ def __init__(self, app):
+ self.app = app
+
+ def __call__(self, environ, start_response):
+ res = self.app(environ, start_response)
+ txn = transaction.get()
+ if not txn.isDoomed():
+ request = environ['zope.request']
+ name, ob = request.traversed[-1]
+ self.annotate(txn, request, ob)
+ return res
+
+ def annotate(self, txn, request, ob):
+ """Set some useful meta-information on the transaction.
+
+ This information is used by the undo framework, for example.
+ """
+ if request.principal is not None:
+ txn.setUser(request.principal.id)
+
+ # Work around methods that are usually used for views
+ bare = removeSecurityProxy(ob)
+ if isinstance(bare, instancemethod):
+ ob = bare.im_self
+
+ # set the location path
+ path = None
+ location = ILocationInfo(ob, None)
+ if location is not None:
+ # Views are made children of their contexts, but that
+ # doesn't necessarily mean that we can fully resolve the
+ # path. E.g. the family tree of a resource cannot be
+ # resolved completely, as the site manager is a dead end.
+ try:
+ path = location.getPath()
+ except (AttributeError, TypeError):
+ pass
+ if path is not None:
+ txn.setExtendedInfo('location', path)
+
+ # set the request type
+ iface = IRequest
+ for iface in providedBy(request):
+ if iface.extends(IRequest):
+ break
+ iface_dotted = '%s.%s' % (iface.__module__, iface.getName())
+ txn.setExtendedInfo('request_type', iface_dotted)
+ return txn
Deleted: Sandbox/shane/republish/zope/pipeline/authenticator.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/authenticator.py 2009-02-12 02:49:46 UTC (rev 96458)
+++ Sandbox/shane/republish/zope/pipeline/authenticator.py 2009-02-12 05:25:08 UTC (rev 96459)
@@ -1,73 +0,0 @@
-
-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
-from zope.security.management import endInteraction
-
-from zope.app.security.interfaces import IAuthentication
-from zope.app.security.interfaces import IFallbackUnauthenticatedPrincipal
-
-
-class Authenticator(object):
- """WSGI app that hooks into Zope-based authentication.
-
- The WSGI environment must contain 'zope.request'.
- """
- implements(IWSGIApplication)
- adapts(IWSGIApplication, IRequest)
-
- def __init__(self, app, marker_request=None):
- self.app = app
-
- def __call__(self, environ, start_response):
- request = environ['zope.request']
- auth = getGlobalSiteManager().getUtility(IAuthentication)
- principal = auth.authenticate(request)
- if principal is None:
- request.traversal_hooks.append(placeful_auth)
- principal = auth.unauthenticatedPrincipal()
- if principal is None:
- # Get the fallback unauthenticated principal
- principal = getUtility(IFallbackUnauthenticatedPrincipal)
- request.principal = principal
-
- newInteraction(request)
- try:
- return self.app(environ, start_response)
- finally:
- endInteraction()
-
- def __repr__(self):
- return '%s(%s)' % (self.__class__.__name__, repr(self.app))
-
-
-def placeful_auth(request, ob):
- """Traversal hook that tries to authenticate in a context"""
-
- if not IUnauthenticatedPrincipal.providedBy(request.principal):
- # We've already got an authenticated user. There's nothing to do.
- # Note that beforeTraversal guarentees that user is not None.
- return
-
- if not ISite.providedBy(ob):
- # We won't find an authentication utility here, so give up.
- return
-
- sm = removeSecurityProxy(ob).getSiteManager()
-
- auth = sm.queryUtility(IAuthentication)
- if auth is None:
- # No auth utility here
- return
-
- # Try to authenticate against the auth utility
- principal = auth.authenticate(request)
- if principal is None:
- principal = auth.unauthenticatedPrincipal()
- if principal is None:
- # nothing to do here
- return
-
- request.setPrincipal(principal)
Modified: Sandbox/shane/republish/zope/pipeline/autotemp.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/autotemp.py 2009-02-12 02:49:46 UTC (rev 96458)
+++ Sandbox/shane/republish/zope/pipeline/autotemp.py 2009-02-12 05:25:08 UTC (rev 96459)
@@ -1,3 +1,16 @@
+##############################################################################
+#
+# Copyright (c) 2009 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.
+#
+##############################################################################
from cStringIO import StringIO
Deleted: Sandbox/shane/republish/zope/pipeline/build.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/build.py 2009-02-12 02:49:46 UTC (rev 96458)
+++ Sandbox/shane/republish/zope/pipeline/build.py 2009-02-12 05:25:08 UTC (rev 96459)
@@ -1,28 +0,0 @@
-
-"""Creates the WSGI pipeline configured by ZCML and the component architecture.
-
-
-"""
-
-from zope.publisher.interfaces import IWSGIApplication
-
-configured_stages = [] # set by pipeline:stages directive
-
-def make_app(configuration, stages=configured_stages):
- stages = list(stages) # make a copy
-
- # the last stage name is the application
- name = stages.pop()
- app = IWSGIApplication(configuration, name=name, default=None)
- if app is None:
- app = IWSGIApplication(name=name)
-
- # the rest are middleware
- while stages:
- name = stages.pop()
- new_app = IWSGIApplication(app, configuration, name=name, default=None)
- if new_app is None:
- new_app = IWSGIApplication(app, name=name)
- app = new_app
-
- return app
Deleted: Sandbox/shane/republish/zope/pipeline/caller.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/caller.py 2009-02-12 02:49:46 UTC (rev 96458)
+++ Sandbox/shane/republish/zope/pipeline/caller.py 2009-02-12 05:25:08 UTC (rev 96459)
@@ -1,118 +0,0 @@
-
-from zope.interface import implements
-from zope.proxy import removeAllProxies
-from zope.publisher.interfaces import IWSGIApplication
-
-
-class Caller(object):
- """WSGI app that calls the traversed object.
-
- Requires 'zope.request', which implements IRequest, in the environment.
- The 'traversed' attribute of the request must be set.
- """
- implements(IWSGIApplication)
-
- def __call__(self, environ, start_response):
- request = environ['zope.request']
- name, ob = request.traversed[-1]
- result = mapply(ob, request.positional_arguments, request)
- response = request.response
- if result is not response:
- response.setResult(result)
- start_response(response.getStatusString(), response.getHeaders())
- return response.consumeBodyIter()
-
- def __repr__(self):
- return '%s()' % self.__class__.__name__
-
-
-_marker = object() # Create a new marker object.
-
-def unwrapMethod(obj):
- """obj -> (unwrapped, wrapperCount)
-
- Unwrap 'obj' until we get to a real function, counting the number of
- unwrappings.
-
- Bail if we find a class or something we can't identify as callable.
- """
- wrapperCount = 0
- unwrapped = obj
-
- for i in range(10):
- bases = getattr(unwrapped, '__bases__', None)
- if bases is not None:
- raise TypeError("mapply() can not call class constructors")
-
- im_func = getattr(unwrapped, 'im_func', None)
- if im_func is not None:
- unwrapped = im_func
- wrapperCount += 1
- elif getattr(unwrapped, 'func_code', None) is not None:
- break
- else:
- unwrapped = getattr(unwrapped, '__call__' , None)
- if unwrapped is None:
- raise TypeError("mapply() can not call %s" % repr(obj))
- else:
- raise TypeError("couldn't find callable metadata, mapply() error on %s"
- % repr(obj))
-
- return unwrapped, wrapperCount
-
-
-def mapply(obj, positional=(), request={}):
- __traceback_info__ = obj
-
- # we need deep access for introspection. Waaa.
- unwrapped = removeAllProxies(obj)
-
- unwrapped, wrapperCount = unwrapMethod(unwrapped)
-
- code = unwrapped.func_code
- defaults = unwrapped.func_defaults
- names = code.co_varnames[wrapperCount:code.co_argcount]
-
- nargs = len(names)
- if not positional:
- args = []
- else:
- args = list(positional)
- if len(args) > nargs:
- given = len(args)
- if wrapperCount:
- given += wrapperCount
- raise TypeError('%s() takes at most %d argument%s(%d given)' % (
- getattr(unwrapped, '__name__', repr(obj)),
- code.co_argcount,
- (code.co_argcount > 1 and 's ' or ' '),
- given))
-
- get = request.get
- nrequired = len(names)
- if defaults:
- nrequired -= len(defaults)
-
- for index in range(len(args), nargs):
- name = names[index]
- v = get(name, _marker)
- if v is _marker:
- if name == 'REQUEST':
- v = request
- elif index < nrequired:
- raise TypeError('Missing argument to %s(): %s' % (
- getattr(unwrapped, '__name__', repr(obj)), name))
- else:
- v = defaults[index - nrequired]
- args.append(v)
-
- args = tuple(args)
-
- if __debug__:
- return debug_call(obj, args)
-
- return obj(*args)
-
-def debug_call(obj, args):
- # The presence of this function allows us to set a pdb breakpoint
- return obj(*args)
Modified: Sandbox/shane/republish/zope/pipeline/configure.zcml
===================================================================
--- Sandbox/shane/republish/zope/pipeline/configure.zcml 2009-02-12 02:49:46 UTC (rev 96458)
+++ Sandbox/shane/republish/zope/pipeline/configure.zcml 2009-02-12 05:25:08 UTC (rev 96459)
@@ -9,7 +9,7 @@
<wsgi:application-list for=".interfaces.IUndecidedRequest" names="
retry
request_factory
- switch
+ switch_pipeline
" />
<wsgi:application-list for="zope.publisher.interfaces.IRequest" names="
@@ -43,7 +43,7 @@
says what kind of request is required, assume IRequest. -->
<wsgi:middleware
- factory=".retry.Retry"
+ factory=".apps.retry.Retry"
name="retry"
for=".interfaces.INoRequest" />
@@ -61,8 +61,8 @@
says what kind of request is required, assume IRequest. -->
<wsgi:application
- factory=".switch.Switch"
- name="switch"
+ factory=".apps.switch.SwitchPipeline"
+ name="switch_pipeline"
for=".interfaces.INoRequest" />
@@ -71,15 +71,15 @@
name="logger" />
<wsgi:middleware
- factory=".rootopen.RootOpener"
+ factory=".apps.rootopen.RootOpener"
name="root_opener" />
<wsgi:middleware
- factory=".txnctl.TransactionController"
+ factory=".apps.txnctl.TransactionController"
name="transaction_controller" />
<wsgi:middleware
- factory=".event.EventNotifier"
+ factory=".apps.notify.EventNotifier"
name="notifier" />
<wsgi:middleware
@@ -87,7 +87,7 @@
name="error_handler" />
<wsgi:middleware
- factory=".authenticator.Authenticator"
+ factory=".apps.authenticator.Authenticator"
name="authenticator" />
<wsgi:middleware
@@ -95,14 +95,13 @@
name="traverser" />
<wsgi:middleware
- factory=".txnctl.TransactionAnnotator"
+ factory=".apps.txnctl.TransactionAnnotator"
name="transaction_annotator" />
<wsgi:application
- factory=".caller.Caller"
+ factory=".apps.caller.Caller"
name="caller" />
-
</configure>
Deleted: Sandbox/shane/republish/zope/pipeline/event.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/event.py 2009-02-12 02:49:46 UTC (rev 96458)
+++ Sandbox/shane/republish/zope/pipeline/event.py 2009-02-12 05:25:08 UTC (rev 96459)
@@ -1,35 +0,0 @@
-
-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
-from zope.publisher.interfaces.event import EndRequestEvent
-
-
-class EventNotifier(object):
- """Fires request-related events.
-
- Fires are BeforeTraverseEvent and EndRequestEvent at the appropriate
- times.
- """
- implements(IWSGIApplication)
- adapts(IWSGIApplication)
-
- def __init__(self, app):
- self.app = app
-
- def __call__(self, environ, start_response):
- request = environ['zope.request']
- request.traversal_hooks.append(self.fireBeforeTraverse)
- try:
- return self.app(environ, start_response)
- finally:
- if request.traversed:
- name, ob = request.traversed[-1]
- else:
- ob = None
- notify(EndRequestEvent(ob, request))
-
- def fireBeforeTraverse(self, request, ob):
- notify(BeforeTraverseEvent(ob, request))
Modified: Sandbox/shane/republish/zope/pipeline/meta.zcml
===================================================================
--- Sandbox/shane/republish/zope/pipeline/meta.zcml 2009-02-12 02:49:46 UTC (rev 96458)
+++ Sandbox/shane/republish/zope/pipeline/meta.zcml 2009-02-12 05:25:08 UTC (rev 96459)
@@ -28,4 +28,11 @@
handler=".zcml.middleware"
/>
+<meta:directive
+ namespace="http://namespaces.zope.org/zope"
+ name="request-factory"
+ schema=".zcml.IRequestFactoryDirective"
+ handler=".zcml.request_factory"
+ />
+
</configure>
Deleted: Sandbox/shane/republish/zope/pipeline/passthrough.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/passthrough.py 2009-02-12 02:49:46 UTC (rev 96458)
+++ Sandbox/shane/republish/zope/pipeline/passthrough.py 2009-02-12 05:25:08 UTC (rev 96459)
@@ -1,10 +0,0 @@
-
-
-def passthrough(app):
- """A passthrough application.
-
- Use this to skip a pipeline step. Register this function
- as the middleware factory for a step you don't want to use.
- The step will be eliminated even from application stack traces.
- """
- return app
Deleted: Sandbox/shane/republish/zope/pipeline/retry.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/retry.py 2009-02-12 02:49:46 UTC (rev 96458)
+++ Sandbox/shane/republish/zope/pipeline/retry.py 2009-02-12 05:25:08 UTC (rev 96459)
@@ -1,66 +0,0 @@
-
-from zope.interface import adapts
-from zope.interface import implements
-from zope.publisher.interfaces import IWSGIApplication
-from zope.publisher.interfaces.exceptions import Retry
-from ZODB.POSException import ConflictError
-
-from zope.pipeline.autotemp import AutoTemporaryFile
-
-
-class Retry(object):
- """Retries requests when a Retry or ConflictError propagates.
-
- This middleware app should enclose the app that creates zope.request.
- It sets an environment variable named 'zope.can_retry'. Error handlers
- should propagate Retry or ConflictError when 'zope.can_retry' is
- true.
- """
- implements(IWSGIApplication)
- adapts(IWSGIApplication)
-
- def __init__(self, app, max_attempts=3):
- self.app = app
- self.max_attempts = max_attempts
-
- def __call__(self, environ, start_response):
- wsgi_input = environ.get('wsgi.input')
- if wsgi_input is not None:
- if not hasattr(wsgi_input, 'seek'):
- # make the input stream rewindable
- f = AutoTemporaryFile()
- f.copyfrom(wsgi_input)
- f.seek(0)
- environ['wsgi.input'] = wsgi_input = f
-
- def retryable_start_response(status, response_headers, exc_info=None):
- start_response_params[:] = [status, response_headers, exc_info]
- tmp = AutoTemporaryFile()
- output_file[:] = [tmp]
- return tmp
-
- attempt = 1
- while attempt < self.max_attempts:
- start_response_params = []
- output_file = []
- environ['zope.can_retry'] = True
- try:
- res = self.app(environ, retryable_start_response)
- except (Retry, ConflictError):
- if 'zope.request' in environ:
- del environ['zope.request']
- if wsgi_input is not None:
- wsgi_input.seek(0)
- attempt += 1
- else:
- if start_response_params:
- dest = start_response(*tuple(start_response_params))
- src = output_file[0]
- src.seek(0)
- src.copyto(dest)
- src.close()
- return res
-
- # try once more, this time without retry support
- environ['zope.can_retry'] = False
- return self.app(environ, start_response)
Deleted: Sandbox/shane/republish/zope/pipeline/rootopen.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/rootopen.py 2009-02-12 02:49:46 UTC (rev 96458)
+++ Sandbox/shane/republish/zope/pipeline/rootopen.py 2009-02-12 05:25:08 UTC (rev 96459)
@@ -1,55 +0,0 @@
-
-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
-
-
-class RootOpener(object):
- """Puts a root object in 'zope.request' of the WSGI environment.
-
- Sets request.traversed to a list with one element.
- Also closes the database connection on the way out.
-
- Special case: if the traversal stack contains "++etc++process",
- instead of opening the database, this uses the utility by that
- name as the root object.
- """
- implements(IWSGIApplication)
- adapts(IWSGIApplication, IZopeConfiguration)
-
- database_name = 'main'
- root_name = 'Application'
- app_controller_name = '++etc++process'
-
- def __init__(self, app, zope_conf):
- self.app = app
- self.db = zope_conf.databases[self.database_name]
-
- def __call__(self, environ, start_response):
- request = environ['zope.request']
-
- # If the traversal stack contains self.app_controller_name,
- # then we should get the app controller rather than look
- # in the database.
- if self.app_controller_name in request.traversal_stack:
- root = getUtility(name=self.app_controller_name)
- request.traversed = [(self.app_controller_name, root)]
- return self.app(environ, start_response)
-
- # Open the database.
- conn = self.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))]
-
- try:
- return self.app(environ, start_response)
- finally:
- conn.close()
Deleted: Sandbox/shane/republish/zope/pipeline/simpletraverser.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/simpletraverser.py 2009-02-12 02:49:46 UTC (rev 96458)
+++ Sandbox/shane/republish/zope/pipeline/simpletraverser.py 2009-02-12 05:25:08 UTC (rev 96459)
@@ -1,19 +0,0 @@
-
-"""
-
-Rules:
-
- * __getitem__ all path elements except ++, @@, maybe +
- * Look up a view at the end using getMultiAdapter().
- * If the view has a capitalized method name matching REQUEST_METHOD,
- traverse to that.
-"""
-
-class SimpleTraverser(object):
-
- def __init__(self, app):
- self.app = app
-
- def __call__(self, environ, start_response):
- request = environ['zope.request']
-
\ No newline at end of file
Deleted: Sandbox/shane/republish/zope/pipeline/switch.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/switch.py 2009-02-12 02:49:46 UTC (rev 96458)
+++ Sandbox/shane/republish/zope/pipeline/switch.py 2009-02-12 05:25:08 UTC (rev 96459)
@@ -1,19 +0,0 @@
-
-
-from zope.interface import implements
-from zope.publisher.interfaces import IWSGIApplication
-
-class Switch(object):
- """WSGI application that switches to a pipeline based on the request type.
-
- Requires 'zope.request' in the environment.
- """
- implements(IWSGIApplication)
-
- def __call__(self, environ, start_response):
- request = environ['zope.request']
- app = IWSGIApplication(request, name='pipeline')
- return app(environ, start_response)
-
- def __repr__(self):
- return '%s()' % self.__class__.__name__
Deleted: Sandbox/shane/republish/zope/pipeline/traverser.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/traverser.py 2009-02-12 02:49:46 UTC (rev 96458)
+++ Sandbox/shane/republish/zope/pipeline/traverser.py 2009-02-12 05:25:08 UTC (rev 96459)
@@ -1,55 +0,0 @@
-
-from zope.interface import adapts
-from zope.interface import implements
-from zope.publisher.interfaces import IWSGIApplication
-
-
-class Traverser(object):
- """Traverses the object graph based on the traversal stack.
-
- Requires 'zope.request' in the WSGI environment.
- """
- implements(IWSGIApplication)
- adapts(IWSGIApplication)
-
- def __init__(self, app):
- self.app = app
-
- def __call__(self, environ, start_response):
- request = environ['zope.request']
- self.traverse(request)
- return self.app(environ, start_response)
-
- def traverse(self, request):
- traversal_stack = request.traversal_stack
- traversal_hooks = request.traversal_hooks
- traversed = request.traversed
-
- root_name, obj = traversed[-1]
- prev_object = None
-
- while True:
- if obj is not prev_object:
- # Call hooks (but not more than once).
- for hook in traversal_hooks:
- hook(request, obj)
-
- if not traversal_stack:
- break
-
- prev_object = obj
-
- # Traverse to the next step.
- name = traversal_stack.pop()
- obj = self.traverse_name(obj, name)
- traversed.append((name, obj))
-
- def traverse_name(self, obj, name):
- pass
-
-
-class HTTPTraverser(Traverser):
- implements(IWSGIApplication)
- adapts(IWSGIApplication)
- request_type = IHTTPRequest
-
Deleted: Sandbox/shane/republish/zope/pipeline/txnctl.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/txnctl.py 2009-02-12 02:49:46 UTC (rev 96458)
+++ Sandbox/shane/republish/zope/pipeline/txnctl.py 2009-02-12 05:25:08 UTC (rev 96459)
@@ -1,92 +0,0 @@
-
-
-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
-from zope.publisher.interfaces import IWSGIApplication
-from zope.security.proxy import removeSecurityProxy
-
-
-class TransactionController(object):
- """WSGI middleware that begins and commits/aborts transactions.
- """
- implements(IWSGIApplication)
- adapts(IWSGIApplication)
-
- def __init__(self, app):
- self.app = app
-
- def __call__(self, environ, start_response):
- transaction.begin()
- try:
- res = self.app(environ, start_response)
- except:
- transaction.abort()
- raise
- txn = transaction.get()
- if txn.isDoomed():
- txn.abort()
- else:
- txn.commit()
- return res
-
-
-class TransactionAnnotator(object):
- """WSGI middleware that annotates transactions.
-
- Requires 'zope.request' in the environment.
- """
- implements(IWSGIApplication)
- adapts(IWSGIApplication)
-
- def __init__(self, app):
- self.app = app
-
- def __call__(self, environ, start_response):
- res = self.app(environ, start_response)
- txn = transaction.get()
- if not txn.isDoomed():
- request = environ['zope.request']
- name, ob = request.traversed[-1]
- self.annotate(txn, request, ob)
- return res
-
- def annotate(self, txn, request, ob):
- """Set some useful meta-information on the transaction.
-
- This information is used by the undo framework, for example.
- """
- if request.principal is not None:
- txn.setUser(request.principal.id)
-
- # Work around methods that are usually used for views
- bare = removeSecurityProxy(ob)
- if isinstance(bare, instancemethod):
- ob = bare.im_self
-
- # set the location path
- path = None
- location = ILocationInfo(ob, None)
- if location is not None:
- # Views are made children of their contexts, but that
- # doesn't necessarily mean that we can fully resolve the
- # path. E.g. the family tree of a resource cannot be
- # resolved completely, as the site manager is a dead end.
- try:
- path = location.getPath()
- except (AttributeError, TypeError):
- pass
- if path is not None:
- txn.setExtendedInfo('location', path)
-
- # set the request type
- iface = IRequest
- for iface in providedBy(request):
- if iface.extends(IRequest):
- break
- iface_dotted = '%s.%s' % (iface.__module__, iface.getName())
- txn.setExtendedInfo('request_type', iface_dotted)
- return txn
Modified: Sandbox/shane/republish/zope/pipeline/zcml.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/zcml.py 2009-02-12 02:49:46 UTC (rev 96458)
+++ Sandbox/shane/republish/zope/pipeline/zcml.py 2009-02-12 05:25:08 UTC (rev 96459)
@@ -184,3 +184,56 @@
adapter(_context, factory=[app_factory], provides=[IWSGIApplication],
for_=[IWSGIApplication, for_], name=name)
+
+
+class IRequestFactoryDirective(Interface):
+ """Link information from a request to a request factory"""
+
+ name = TextLine(
+ title=_('Name'),
+ description=_('The name of the request factory.'))
+
+ factory = GlobalObject(
+ title=_('Factory'),
+ description=_('The request factory'))
+
+ protocols = Tokens(
+ title=_('Protocols'),
+ description=_('A list of protocols to support. Defaults to "HTTP".'),
+ value_type=TextLine(),
+ required=False)
+
+ methods = Tokens(
+ title=u'Methods',
+ description=(u'A list of HTTP method names. If the method is a "*", '
+ u'then all methods will match. Example: "GET POST"'),
+ value_type=TextLine(),
+ required=False)
+
+ mimetypes = Tokens(
+ title=u'Mime Types',
+ description=(u'A list of content/mime types of the request. If the '
+ u'type is a "*" then all types will be matched. '
+ u'Example: "text/html text/xml"'),
+ value_type=TextLine(),
+ required=False)
+
+ priority = Int(
+ title=u'Priority',
+ description=(u'A priority key used to decide between coexistent'
+ ' request factories.'),
+ required=False)
+
+def request_factory(_context, name, factory,
+ protocols=['HTTP'], methods=['*'], mimetypes=['*'], priority=0):
+
+ factory = factory()
+
+ for protocol in protocols:
+ for method in methods:
+ for mimetype in mimetypes:
+ _context.action(
+ discriminator = (method, mimetype, priority),
+ callable = factoryRegistry.register,
+ args = (protocol, method, mimetype, name, priority, factory)
+ )
More information about the Checkins
mailing list