[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