[Zope3-checkins] CVS: Zope3/src/zope/app/publication - __init__.py:1.2 browser.py:1.2 configure.zcml:1.2 http.py:1.2 publicationtraverse.py:1.2 traversers.py:1.2 vfs.py:1.2 xmlrpc.py:1.2 zopepublication.py:1.2
Jim Fulton
jim@zope.com
Wed, 25 Dec 2002 09:14:09 -0500
Update of /cvs-repository/Zope3/src/zope/app/publication
In directory cvs.zope.org:/tmp/cvs-serv15352/src/zope/app/publication
Added Files:
__init__.py browser.py configure.zcml http.py
publicationtraverse.py traversers.py vfs.py xmlrpc.py
zopepublication.py
Log Message:
Grand renaming:
- Renamed most files (especially python modules) to lower case.
- Moved views and interfaces into separate hierarchies within each
project, where each top-level directory under the zope package
is a separate project.
- Moved everything to src from lib/python.
lib/python will eventually go away. I need access to the cvs
repository to make this happen, however.
There are probably some bits that are broken. All tests pass
and zope runs, but I haven't tried everything. There are a number
of cleanups I'll work on tomorrow.
=== Zope3/src/zope/app/publication/__init__.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:09 2002
+++ Zope3/src/zope/app/publication/__init__.py Wed Dec 25 09:13:08 2002
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.
=== Zope3/src/zope/app/publication/browser.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:09 2002
+++ Zope3/src/zope/app/publication/browser.py Wed Dec 25 09:13:08 2002
@@ -0,0 +1,84 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""XXX short summary goes here.
+
+XXX longer description goes here.
+
+$Id$
+"""
+__metaclass__ = type
+
+from zope.app.publication.publicationtraverse \
+ import PublicationTraverser as PublicationTraverser_
+from zope.publisher.interfaces.browser import IBrowserPublisher
+from zope.component import queryAdapter
+
+class PublicationTraverser(PublicationTraverser_):
+
+ def traverseRelativeURL(self, request, ob, path):
+
+ ob = self.traversePath(request, ob, path)
+
+ while 1:
+ adapter = queryAdapter(ob, IBrowserPublisher)
+ if adapter is None:
+ return ob
+ ob, path = adapter.browserDefault(request)
+ if not path:
+ return ob
+
+ ob = self.traversePath(request, ob, path)
+
+
+"""
+
+Revision information:
+$Id$
+"""
+
+from zope.app.publication.http import ZopeHTTPPublication
+from zope.publisher.interfaces.browser import IBrowserPublisher
+from zope.component import queryView
+from zope.proxy.context import ContextWrapper
+from zope.proxy.introspection import removeAllProxies
+
+class BrowserPublication(ZopeHTTPPublication):
+ """Web browser publication handling."""
+
+ def getDefaultTraversal(self, request, ob):
+
+ r = ()
+
+ if IBrowserPublisher.isImplementedBy(removeAllProxies(ob)):
+ r = ob.browserDefault(request)
+ else:
+ adapter = queryView(ob, '_traverse', request , None)
+ if adapter is not None:
+ r = adapter.browserDefault(request)
+ else:
+ return (ob, None)
+
+ if r[0] is ob: return r
+
+ wrapped = ContextWrapper(r[0], ob, name=None)
+ return (wrapped, r[1])
+
+# For now, have a factory that returns a singleton
+class PublicationFactory:
+
+ def __init__(self, db):
+ self.__pub = BrowserPublication(db)
+
+ def __call__(self):
+ return self.__pub
=== Zope3/src/zope/app/publication/configure.zcml 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:09 2002
+++ Zope3/src/zope/app/publication/configure.zcml Wed Dec 25 09:13:08 2002
@@ -0,0 +1,19 @@
+<zopeConfigure
+ xmlns='http://namespaces.zope.org/zope'
+ xmlns:browser='http://namespaces.zope.org/browser'
+ xmlns:xmlrpc='http://namespaces.zope.org/xmlrpc'
+>
+
+<browser:view name="_traverse"
+ for="zope.interface.Interface"
+ factory="zope.app.publication.traversers.SimpleComponentTraverser" />
+
+<browser:view name="_traverse"
+ for="zope.app.interfaces.content.file.IFileContent"
+ factory="zope.app.publication.traversers.FileContentTraverser" />
+
+ <xmlrpc:view name="_traverse"
+ for="zope.interface.Interface"
+ factory="zope.app.publication.traversers.SimpleComponentTraverser" />
+
+</zopeConfigure>
=== Zope3/src/zope/app/publication/http.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:09 2002
+++ Zope3/src/zope/app/publication/http.py Wed Dec 25 09:13:08 2002
@@ -0,0 +1,23 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+from zope.app.publication.zopepublication import ZopePublication
+
+class ZopeHTTPPublication(ZopePublication):
+ "HTTP-specific support"
+ # XXX do we need this?
=== Zope3/src/zope/app/publication/publicationtraverse.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:09 2002
+++ Zope3/src/zope/app/publication/publicationtraverse.py Wed Dec 25 09:13:08 2002
@@ -0,0 +1,113 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+from zope.component import queryView, getService
+from zope.publisher.interfaces import NotFound
+from types import StringTypes
+from zope.proxy.context import ContextWrapper
+
+from zope.app.interfaces.container import IWriteContainer
+from zope.proxy.introspection import removeAllProxies
+from zope.app.traversing.namespaces import namespaceLookup
+from zope.app.traversing.parameterparsing import parameterizedNameParse
+from zope.publisher.interfaces import IPublishTraverse
+
+class DuplicateNamespaces(Exception):
+ """More than one namespace was specified in a request"""
+
+class UnknownNamespace(Exception):
+ """A parameter specified an unknown namespace"""
+
+class PublicationTraverse:
+
+ def traverseName(self, request, ob, name):
+ nm = name # the name to look up the object with
+
+ if name and name[:1] in '@+':
+ # Process URI segment parameters.
+ ns, nm, parms = parameterizedNameParse(name)
+
+ unknown_parms = ()
+ for pname, pval in parms:
+ pset = getattr(self, "_parameterSet%s" % pname, self) # marker
+ if pset is self:
+ # We don't know about this one
+ unknown_parms += ((pname, pval),)
+ else:
+ pset(pname, pval, request)
+
+ if ns:
+ ob2 = namespaceLookup(name, ns, nm, unknown_parms, ob, request)
+ return ob2
+
+ if unknown_parms:
+ nm = "%s;%s" % (
+ nm,
+ ';'.join(["%s=%s" % (parm[0], parm[1])
+ for parm in unknown_parms])
+ )
+
+ if not nm:
+ # Just set params, so skip
+ return ob
+
+ if nm == '.':
+ return ob
+
+ if IPublishTraverse.isImplementedBy(removeAllProxies(ob)):
+ ob2 = ob.publishTraverse(request, nm)
+ else:
+ adapter = queryView(ob, '_traverse', request, self) # marker
+ if adapter is not self:
+ ob2 = adapter.publishTraverse(request, nm)
+ else:
+ raise NotFound(ob, name, request)
+
+ return ContextWrapper(ob2, ob, name=name)
+
+class PublicationTraverser(PublicationTraverse):
+
+ def traversePath(self, request, ob, path):
+
+ if isinstance(path, StringTypes):
+ path = path.split('/')
+ if len(path) > 1 and not path[-1]:
+ # Remove trailing slash
+ path.pop()
+ else:
+ path = list(path)
+
+ # Remove dingle dots
+ path = [x for x in path if x != '.']
+
+ path.reverse()
+
+ # Remove double dots
+ while '..' in path:
+ l = path.index('..')
+ if l < 0 or l+2 > len(path):
+ break
+ del path[l:l+2]
+
+ pop = path.pop
+
+ while path:
+ name = pop()
+ ob = self.traverseName(request, ob, name)
+
+ return ob
=== Zope3/src/zope/app/publication/traversers.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:09 2002
+++ Zope3/src/zope/app/publication/traversers.py Wed Dec 25 09:13:08 2002
@@ -0,0 +1,110 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"$Id"
+
+__metaclass__ = type
+
+
+from zope.publisher.interfaces import Unauthorized, NotFound, DebugError
+from zope.publisher.interfaces.browser import IBrowserPublisher
+from zope.publisher.interfaces.xmlrpc import IXMLRPCPublisher
+from zope.component \
+ import queryView, getView, getDefaultViewName
+from zope.component.exceptions import ComponentLookupError
+
+class SimpleComponentTraverser:
+ """Browser traverser for simple components that can only traverse to views
+ """
+ __implements__ = IBrowserPublisher, IXMLRPCPublisher
+
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+ def browserDefault(self, request):
+ ob = self.context
+
+ view_name = getDefaultViewName(ob, request)
+
+ return ob, (view_name,)
+
+ def publishTraverse(self, request, name):
+ ob = self.context
+ from zope.component.view import viewService
+ view = queryView(ob, name, request)
+ if view is None:
+ raise NotFound(ob, name)
+ return view
+
+class FileContentTraverser(SimpleComponentTraverser):
+ """Browser traverser for file content.
+
+ The default view for file content has effective URLs that don't end in
+ /. In particular, if the content inclused HTML, relative links in
+ the HTML are relative to the container the content is in.
+
+ """
+
+ def browserDefault(self, request):
+ ob = self.context
+
+ view_name = getDefaultViewName(ob, request)
+ view = self.publishTraverse(request, view_name)
+ if hasattr(view, 'browserDefault'):
+ view, path = view.browserDefault(request)
+ if len(path) == 1:
+ view = view.publishTraverse(request, path[0])
+ path = ()
+ else:
+ path = ()
+
+ return view, path
+
+class TestTraverser:
+ "Bobo-style traverser, mostly useful for testing"
+
+ __implements__ = IBrowserPublisher
+
+ def __init__(self, context, request):
+ self.context = context
+
+ def browserDefault(self, request):
+ ob = self.context
+
+ if hasattr(ob, '__implements__'):
+
+ view_name = getDefaultViewName(ob, request)
+
+ return ob, (("@@%s" % view_name),)
+
+ return ob, ()
+
+ def publishTraverse(self, request, name):
+ ob = self.context
+ if name.startswith('@@'):
+ return getView(ob, name[6:], request)
+
+ if name.startswith('_'):
+ raise Unauthorized("Name %s begins with an underscore" % `name`)
+
+ subob = getattr(ob, name, self) # self is marker here
+ if subob is self:
+ # no attribute
+ try:
+ subob = ob[name]
+ except (KeyError, IndexError,
+ TypeError, AttributeError):
+ raise NotFound(ob, name, request)
+
+ return subob
=== Zope3/src/zope/app/publication/vfs.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:09 2002
+++ Zope3/src/zope/app/publication/vfs.py Wed Dec 25 09:13:08 2002
@@ -0,0 +1,40 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+from zope.app.publication.zopepublication import ZopePublication
+
+from zope.component import queryView
+from zope.publisher.interfaces import NotFound
+from zope.publisher.publish import mapply
+
+
+class VFSPublication(ZopePublication):
+ """The Publication will do all the work for the VFS"""
+
+
+ def callObject(self, request, ob):
+
+ view = queryView(ob, 'vfs', request, self)
+ #view = ob
+
+ if view is not self:
+ method = getattr(view, request.method)
+ else:
+ raise NotFound(ob, 'vfs', request)
+
+ return mapply(method, request.getPositionalArguments(), request)
=== Zope3/src/zope/app/publication/xmlrpc.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:09 2002
+++ Zope3/src/zope/app/publication/xmlrpc.py Wed Dec 25 09:13:08 2002
@@ -0,0 +1,45 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+from zope.proxy.introspection import removeAllProxies
+from zope.app.publication.http import ZopeHTTPPublication
+
+class XMLRPCPublication(ZopeHTTPPublication):
+ """XML-RPC publication handling.
+
+ There is nothing special here right now.
+ """
+
+ def traverseName(self, request, ob, name):
+
+ naked_ob = removeAllProxies(ob)
+ if hasattr(ob, name):
+ return getattr(ob, name)
+ else:
+ return super(XMLRPCPublication, self).traverseName(request,
+ ob, name)
+
+
+# For now, have a factory that returns a singleton
+class XMLRPCPublicationFactory:
+
+ def __init__(self, db):
+ self.__pub = XMLRPCPublication(db)
+
+ def __call__(self):
+ return self.__pub
=== Zope3/src/zope/app/publication/zopepublication.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:09 2002
+++ Zope3/src/zope/app/publication/zopepublication.py Wed Dec 25 09:13:08 2002
@@ -0,0 +1,253 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+import sys
+import logging
+
+from zope.component import getService
+from zope.component.exceptions import ComponentLookupError
+from zodb.interfaces import ConflictError
+
+from zope.publisher.base import DefaultPublication
+from zope.publisher.publish import mapply
+from zope.publisher.interfaces import Retry
+
+from zope.security.securitymanagement import getSecurityManager
+from zope.security.securitymanagement import newSecurityManager
+from zope.security.checker import ProxyFactory
+
+from zope.proxy.introspection import removeAllProxies
+
+from zope.app.interfaces.services.service \
+ import IServiceManagerContainer
+
+from zope.exceptions import Unauthorized
+
+from zope.app.applicationcontrol.applicationcontrol \
+ import applicationControllerRoot
+
+from zope.app.security.registries.principalregistry \
+ import principalRegistry as prin_reg
+
+from zope.app.interfaces.security \
+ import IUnauthenticatedPrincipal
+
+from zope.app.publication.publicationtraverse import PublicationTraverse
+
+from zope.proxy.context import ContextWrapper
+
+# XXX Should this be imported here?
+from transaction import get_transaction
+
+class Cleanup:
+ def __init__(self, f):
+ self.__del__ = f
+
+
+class ZopePublication(object, PublicationTraverse, DefaultPublication):
+ """Base Zope publication specification."""
+
+ version_cookie = 'Zope-Version'
+ root_name = 'Application'
+
+ def __init__(self, db):
+ # db is a ZODB.DB.DB object.
+ self.db = db
+
+ def beforeTraversal(self, request):
+
+ # Try to authenticate against the default global registry.
+ p = prin_reg.authenticate(request)
+ if p is None:
+ p = prin_reg.unauthenticatedPrincipal()
+ if p is None:
+ raise Unauthorized # If there's no default principal
+
+ newSecurityManager(p.getId())
+ request.user = p
+ get_transaction().begin()
+
+ def _maybePlacefullyAuthenticate(self, request, ob):
+ if not IUnauthenticatedPrincipal.isImplementedBy(request.user):
+ # We've already got an authenticated user. There's nothing to do.
+ # Note that beforeTraversal guarentees that user is not None.
+ return
+
+ if not IServiceManagerContainer.isImplementedBy(ob):
+ # We won't find an authentication service here, so give up.
+ return
+
+ sm = removeAllProxies(ob).queryServiceManager()
+ if sm is None:
+ # No service manager here, and thus no auth service
+ return
+
+ sm = ContextWrapper(sm, ob, name="++etc++Services")
+
+ auth_service = sm.get('Authentication')
+ if auth_service is None:
+ # No auth service here
+ return
+
+ # Try to authenticate against the auth service
+ principal = auth_service.authenticate(request)
+ if principal is None:
+ principal = auth_service.unauthenticatedPrincipal()
+ if principal is None:
+ # nothing to do here
+ return
+
+ newSecurityManager(principal.getId())
+ request.user = principal
+
+
+ def callTraversalHooks(self, request, ob):
+ # Call __before_publishing_traverse__ hooks
+
+ # This is also a handy place to try and authenticate.
+ self._maybePlacefullyAuthenticate(request, ob)
+
+ def afterTraversal(self, request, ob):
+ #recordMetaData(object, request)
+ self._maybePlacefullyAuthenticate(request, ob)
+
+
+ def openedConnection(self, conn):
+ # Hook for auto-refresh
+ pass
+
+ def getApplication(self, request):
+
+ # If the first name is '++etc++ApplicationControl', then we should
+ # get it rather than look in the database!
+ stack = request.getTraversalStack()
+
+ if '++etc++ApplicationController' in stack:
+ return applicationControllerRoot
+
+ # Open the database.
+ version = request.get(self.version_cookie, '')
+ conn = self.db.open(version)
+
+ cleanup = Cleanup(conn.close)
+ request.hold(cleanup) # Close the connection on request.close()
+
+ self.openedConnection(conn)
+## conn.setDebugInfo(getattr(request, 'environ', None), request.other)
+
+ root = conn.root()
+ app = root.get(self.root_name, None)
+
+ if app is None:
+ raise SystemError, "Zope Application Not Found"
+
+ return ProxyFactory(app)
+
+ def getDefaultTraversal(self, request, ob):
+ return ob, None
+
+ def callObject(self, request, ob):
+ return mapply(ob, request.getPositionalArguments(), request)
+
+ def afterCall(self, request):
+ get_transaction().commit()
+
+ def handleException(self, object, request, exc_info, retry_allowed=1):
+ try:
+ # Abort the transaction.
+ get_transaction().abort()
+
+ try:
+ errService = getService(object,'ErrorReportingService')
+ except ComponentLookupError:
+ pass
+ else:
+ try:
+ errService.raising(exc_info, request)
+ # It is important that an error in errService.raising
+ # does not propagate outside of here. Otherwise, nothing
+ # meaningful will be returned to the user.
+ #
+ # The error reporting service should not be doing database
+ # stuff, so we shouldn't get a conflict error.
+ # Even if we do, it is more important that we log this
+ # error, and proceed with the normal course of events.
+ # We should probably (somehow!) append to the standard
+ # error handling that this error occurred while using
+ # the ErrorReportingService, and that it will be in
+ # the zope log.
+ except:
+ logging.getLogger('SiteError').exception(
+ 'Error while reporting an error to the '
+ 'ErrorReportingService')
+
+ # Delegate Unauthorized errors to the authentication service
+ # XXX Is this the right way to handle Unauthorized? We need
+ # to understand this better.
+ if isinstance(exc_info[1], Unauthorized):
+ sm = getSecurityManager()
+ id = sm.getPrincipal()
+ prin_reg.unauthorized(id, request) # May issue challenge
+ request.response.handleException(exc_info)
+ return
+
+ # XXX This is wrong. Should use getRequstView:
+ #
+ #
+ # # Look for a component to handle the exception.
+ # traversed = request.traversed
+ # if traversed:
+ # context = traversed[-1]
+ # #handler = getExceptionHandler(context, t, IBrowserPublisher)
+ # handler = None # no getExceptionHandler() exists yet.
+ # if handler is not None:
+ # handler(request, exc_info)
+ # return
+
+ # Convert ConflictErrors to Retry exceptions.
+ if retry_allowed and isinstance(exc_info[1], ConflictError):
+ logger.getLogger('ZopePublication').warn(
+ 'Competing writes/reads at %s',
+ request.get('PATH_INFO', '???'),
+ exc_info=True)
+ raise Retry
+
+ # Let the response handle it as best it can.
+ # XXX Is this what we want in the long term?
+ response = request.response
+ response.handleException(exc_info)
+ return
+ finally:
+ # Avoid leaking
+ exc_info = 0
+
+
+ def _parameterSetskin(self, pname, pval, request):
+ request.setViewSkin(pval)
+
+class DebugPublication(object):
+
+ class call_wrapper:
+
+ def __init__(self, ob):
+ self.__ob = ob
+
+ def __getattr__(self, name):
+ return getattr(self.__ob, name)
+
+ def __call__(self, *args, **kw):
+ self.__ob(*args, **kw)
+
+ def callObject(self, request, ob):
+ return mapply(self.call_wrapper(ob),
+ request.getPositionalArguments(), request)