[Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher - IApplicationResponse.py:1.1.2.1 BaseRequest.py:1.1.2.23.4.2 BaseResponse.py:1.1.2.8.6.2 IApplicationRequest.py:1.1.2.1.2.1 IPublication.py:1.1.2.9.6.2 IPublicationRequest.py:1.1.2.1.2.1 IPublisherRequest.py:1.1.2.1.2.1 IPublisherResponse.py:1.1.2.1.2.1 Publish.py:1.1.2.13.6.2
Jim Fulton
jim@zope.com
Wed, 20 Mar 2002 18:43:02 -0500
Update of /cvs-repository/Zope3/lib/python/Zope/Publisher
In directory cvs.zope.org:/tmp/cvs-serv21411/Zope/Publisher
Modified Files:
Tag: Zope3-publisher-refactor-branch
BaseRequest.py BaseResponse.py IApplicationRequest.py
IPublication.py IPublicationRequest.py IPublisherRequest.py
IPublisherResponse.py Publish.py
Added Files:
Tag: Zope3-publisher-refactor-branch
IApplicationResponse.py
Log Message:
Began significant refactoring of publication framework.
- Added accessor functions, getResponse and getPublication.
- Moved some methods between existing interfaces as seem best, and
added new new interfaces.
- Getting rid of payloads.
=== Added File Zope3/lib/python/Zope/Publisher/IApplicationResponse.py ===
##############################################################################
#
# 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
#
##############################################################################
"""
Revision information:
$Id: IApplicationResponse.py,v 1.1.2.1 2002/03/20 23:42:31 jim Exp $
"""
from Interface import Interface
class IApplicationResponse(Interface):
"""Features that support application logic
"""
def write(string):
"""Output a atring to the response body.
"""
=== Zope3/lib/python/Zope/Publisher/BaseRequest.py 1.1.2.23.4.1 => 1.1.2.23.4.2 ===
from cgi import escape
from types import StringType
-from Zope.ComponentArchitecture.IViewService import IViewRequest
from BaseResponse import BaseResponse
from IApplicationRequest import IApplicationRequest
from IPublisherRequest import IPublisherRequest
from IPublicationRequest import IPublicationRequest
-class IRequest(IPublisherRequest, IPublicationRequest, IApplicationRequest,
- IViewRequest):
+class IRequest(IPublisherRequest, IPublicationRequest, IApplicationRequest):
"""The basic request contract
"""
@@ -56,32 +54,126 @@
self.__body_instream = body_instream
self.__held = ()
- def getPositionalArguments(self):
- return self.__args
-
- def _createResponse(self, outstream):
- # Should be overridden by subclasses
- return BaseResponse(outstream)
- def close(self):
- self._other.clear()
- self.__held = () # Release held objects
- self.__traversed = None
+ ############################################################
+ # Implementation methods for interface
+ # Zope.Publisher.BaseRequest.IRequest
- def processInputs(self):
- """Do any initialization that could raise errors
- """
+ ######################################
+ # from: Zope.Publisher.IPublisherRequest.IPublisherRequest
def getPublication(self):
+ 'See Zope.Publisher.IPublisherRequest.IPublisherRequest'
return self.__publication
+ def processInputs(self):
+ 'See Zope.Publisher.IPublisherRequest.IPublisherRequest'
+ # Nothing to do here
+
+ def retry(self):
+ 'See Zope.Publisher.IPublisherRequest.IPublisherRequest'
+ raise TypeError('Retry is not supported')
+
def setPublication(self, pub):
+ 'See Zope.Publisher.IPublisherRequest.IPublisherRequest'
self.__publication = pub
- def getResponse(self, default=None):
+ def supportsRetry(self):
+ 'See Zope.Publisher.IPublisherRequest.IPublisherRequest'
+ return 0
+
+ def traverse(self, object):
+ 'See Zope.Publisher.IPublisherRequest.IPublisherRequest'
+
+ publication = self.getPublication()
+
+ to_traverse = self.__traversal_stack
+ prev_object = None
+ while 1:
+ if object is not prev_object:
+ # Invoke hooks (but not more than once).
+ publication.callTraversalHooks(self, object)
+ # A hook may have called changeTraversalStack().
+ to_traverse = self.__traversal_stack
+ prev_object = object
+
+ if to_traverse:
+ # Traverse to the next step.
+ entry_name = to_traverse.pop()
+ subobject = publication.traverseName(
+ self, object, entry_name)
+ object = subobject
+ else:
+ # Finished traversal.
+ break
+
+ return object
+
+ ######################################
+ # from: Zope.Publisher.IPublicationRequest.IPublicationRequest
+
+ def close(self):
+ 'See Zope.Publisher.IPublicationRequest.IPublicationRequest'
+ self._other.clear()
+ self.__dict__.clear()
+
+ def getPositionalArguments(self):
+ 'See Zope.Publisher.IPublicationRequest.IPublicationRequest'
+ return self.__args
+
+ def getResponse(self):
+ 'See Zope.Publisher.IPublicationRequest.IPublicationRequest'
return self.__response
- def getBody(self, default=None):
+ def getTraversalStack(self):
+ 'See Zope.Publisher.IPublicationRequest.IPublicationRequest'
+ return self.__traversal_stack
+
+ def hold(self, object):
+ 'See Zope.Publisher.IPublicationRequest.IPublicationRequest'
+ self._held = self._held + (object,)
+
+ def setTraversalStack(self, stack):
+ 'See Zope.Publisher.IPublicationRequest.IPublicationRequest'
+ self.__traversal_stack = stack
+
+ _viewskin = ''
+
+ def setViewSkin(self, skin):
+ 'See Zope.Publisher.IPublicationRequest.IPublicationRequest'
+ self._viewskin = skin
+
+ ######################################
+ # from: Zope.ComponentArchitecture.IViewService.IViewRequest
+
+ def getViewSkin(self):
+ 'See Zope.ComponentArchitecture.IViewService.IViewRequest'
+ return self._viewskin
+
+ _viewtype = None
+
+ def getViewType(self):
+ 'See Zope.ComponentArchitecture.IViewService.IViewRequest'
+ return self._viewtype
+
+ # This is not part of the interface:
+ def setViewType(self, viewtype):
+ '''Set the view type.
+
+ This method will normally only be called in tests, which will allow
+ us to use a simpler Request set-up.'''
+
+ # XXX This will probably go away
+
+ self._viewtype = viewtype
+
+
+ ######################################
+ # from: Zope.Publisher.IApplicationRequest.IApplicationRequest
+
+ __body = None
+ def getBody(self):
+ 'See Zope.Publisher.IApplicationRequest.IApplicationRequest'
body = self.__body
if body is None:
s = self.__body_instream
@@ -91,145 +183,96 @@
s.seek(0)
body = s.read()
s.seek(p)
- self._body = body
+ self.__body = body
return body
- def getBodyFile(self, default=None):
- return self.body_instream
-
- def get(self, key, default=None):
-
- result = self._other.get(key, self)
- if result is not self: return result
-
- result = self._common.get(key, self)
- if result is not self: return result
-
- result = self._environ.get(key, self)
- if result is not self: return result
-
- return default
-
- def __getitem__(self, key):
- result = self.get(key, _marker)
- if result is _marker:
- raise KeyError, key
- else:
- return result
+ def getBodyFile(self):
+ 'See Zope.Publisher.IApplicationRequest.IApplicationRequest'
+ return self.__body_instream
+
+ ######################################
+ # from: Interface.Common.Mapping.IEnumerableMapping
+
+ def __len__(self):
+ 'See Interface.Common.Mapping.IEnumerableMapping'
+ return len(self._common) + len(self._other) + len(self._environ)
- def has_key(self, key):
- return self.get(key, _marker) is not _marker
+ def items(self):
+ 'See Interface.Common.Mapping.IEnumerableMapping'
+ result = []
+ get = self.get
+ for k in self.keys():
+ result.append((k, get(k)))
+ return result
def keys(self):
+ 'See Interface.Common.Mapping.IEnumerableMapping'
keys = {}
keys.update(self._common)
keys.update(self._other)
keys.update(self._environ)
return keys.keys()
- def items(self):
- result = []
- get = self.get
- for k in self.keys():
- result.append((k, get(k)))
- return result
-
def values(self):
+ 'See Interface.Common.Mapping.IEnumerableMapping'
result = []
get = self.get
for k in self.keys():
result.append(get(k))
return result
- def __str__(self):
- L1 = self.items()
- L1.sort()
- return "\n".join(map(lambda item: "%s:\t%s" % item, L1))
-
- def __repr__(self):
- # Returns a *short* string.
- return '<%s instance at 0x%x, URL=%s>' % (
- str(self.__class__), id(self), `self.URL`)
-
- def setPathSuffix(self, steps):
- """
- Adds the specified steps to the URL, overriding
- publication.getDefaultTraversal().
- """
- self.__path_suffix = steps
-
- def getTraversalStack(self):
- return self.__traversal_stack
+ ######################################
+ # from: Interface.Common.Mapping.IReadMapping
- def setTraversalStack(self, stack):
- self.__traversal_stack = stack
+ def __getitem__(self, key):
+ 'See Interface.Common.Mapping.IReadMapping'
+ result = self.get(key, _marker)
+ if result is _marker:
+ raise KeyError, key
+ else:
+ return result
+ def get(self, key, default=None):
+ 'See Interface.Common.Mapping.IReadMapping'
+ result = self._other.get(key, self)
+ if result is not self: return result
- def traverse(self, publication, object):
- """
- Traverses to an object and returns it.
- Private.
- """
- to_traverse = self.__traversal_stack
- prev_object = None
- while 1:
- if object is not prev_object:
- # Invoke hooks (but not more than once).
- publication.callTraversalHooks(self, object)
- # A hook may have called changeTraversalStack().
- to_traverse = self.__traversal_stack
- prev_object = object
+ result = self._common.get(key, self)
+ if result is not self: return result
- if to_traverse:
- # Traverse to the next step.
- entry_name = to_traverse.pop()
- subobject = publication.traverseName(
- self, object, entry_name)
- object = subobject
- else:
- # Finished traversal.
- break
+ result = self._environ.get(key, self)
+ if result is not self: return result
- return object
+ return default
- def supports_retry(self):
- return 0
+ #
+ ############################################################
- def hold(self, object):
- """
- Holds a reference to an object to delay its destruction until mine
- """
- self._held = self._held + (object,)
+ def _createResponse(self, outstream):
+ # Should be overridden by subclasses
+ return BaseResponse(outstream)
+ def __nonzero__(self):
+ # This is here to avoid calling __len__ for boolean tests
+ return 1
- # Implementation methods for interface
- # Zope.ComponentArchitecture.IViewService.IViewRequest
+ def __str__(self):
+ L1 = self.items()
+ L1.sort()
+ return "\n".join(map(lambda item: "%s:\t%s" % item, L1))
- # Base classes might provide different attributes for this
+ def __repr__(self):
+ # Returns a *short* string.
+ return '<%s instance at 0x%x, URL=%s>' % (
+ str(self.__class__), id(self), `self.URL`)
- _viewskin = ''
- _viewtype = None
-
- def getViewSkin(self):
- '''See interface IViewRequest'''
- return self._viewskin
- def setViewSkin(self, skin):
- ''' add the view skin '''
-
- self._viewskin = skin
- def getViewType(self):
- '''See interface IViewRequest'''
- return self._viewtype
- def setViewType(self, viewtype):
- ''' set the view type '''
- self._viewtype = viewtype
=== Zope3/lib/python/Zope/Publisher/BaseResponse.py 1.1.2.8.6.1 => 1.1.2.8.6.2 ===
from Exceptions import Unauthorized
+import traceback
class BaseResponse(object):
"""Base Response Class
@@ -29,100 +30,26 @@
def __init__(self, outstream):
self.outstream = outstream
- def setDebugMode(self, d):
- self.debug_mode = d
-
- def setStatus(self, status, reason=None):
- self.status = status
-
- def setHeader(self, name, value):
- self.headers[name] = value
-
- __setitem__ = setHeader
-
def outputBody(self):
+ """Output the response body.
"""
- Output the response body.
- """
- self.outstream.write(str(self))
+ self.outstream.write(self._getBody())
+
+ def write(self, string):
+ self.body += string
def setBody(self, body):
self.body = body
- def setBase(self,base):
- 'Sets the base URL for the returned document.'
- self.base=base
-
- def getBase(self):
- ' return the base url '
- return self.base
-
- def getStatus(self):
- 'Returns the current HTTP status code as an integer. '
- return self.status
-
- def setCookie(self,name,value,**kw):
- '''
- Sets an HTTP cookie on the browser
-
- The response will include an HTTP header that sets a cookie on
- cookie-enabled browsers with a key "name" and value
- "value". This overwrites any previously set value for the
- cookie in the Response object.
- '''
- cookies=self.cookies
- if cookies.has_key(name):
- cookie=cookies[name]
- else: cookie=cookies[name]={}
- for k, v in kw.items():
- cookie[k]=v
- cookie['value']=value
-
- def getHeader(self, name):
- '''
- Gets a header value
-
- Returns the value associated with a HTTP return header, or
- "None" if no such header has been set in the response
- yet.
- '''
- return self.headers.get(name, None)
-
- def __getitem__(self, name):
- 'Gets the value of an output header'
- return self.headers[name]
-
- def getBody(self):
+ def _getBody(self):
'Returns a string representing the currently set body.'
return self.body
- def __str__(self):
- return str(self.body)
-
- def __repr__(self):
- return '%s(%s)' % (self.__class__.__name__, `self.body`)
-
- def flush(self):
- pass
-
- def write(self,data):
- """
- Implements the stream output interface.
-
- HTML data may be returned using a stream-oriented interface.
- This allows the browser to display partial results while
- computation of a response to proceed.
-
- The published object should first set any output headers or
- cookies on the response object.
-
- Note that published objects must not generate any errors
- after beginning stream-oriented output.
- """
- self.body = self.body + data
-
def handleException(self, exc_info):
- import traceback
traceback.print_exception(
exc_info[0], exc_info[1], exc_info[2], 100, self)
+ def retry(self):
+ return self.__class__(self.outstream)
+
+
=== Zope3/lib/python/Zope/Publisher/IApplicationRequest.py 1.1.2.1 => 1.1.2.1.2.1 ===
"""
-from Interface import Interface
from Interface.Common.Mapping import IEnumerableMapping
class IApplicationRequest(IEnumerableMapping):
=== Zope3/lib/python/Zope/Publisher/IPublication.py 1.1.2.9.6.1 => 1.1.2.9.6.2 ===
class IPublication (Interface):
- """
- Object publication framework.
+ """Object publication framework.
+
+ The responsibility of publication objects is to provide
+ application hooks for the publishing process. This allows
+ application-specific tasks, such as connecting to databases,
+ managing transactions, and setting security contexts to be invoked
+ during the publishing process.
+
"""
# The order of the hooks mostly corresponds with the order in which
# they are invoked.
@@ -39,35 +45,31 @@
Returns the subobject.
"""
- def getDefaultTraversal(request, ob):
- """
- Allows a default view to be added to traversal.
- Returns (ob, steps_reversed).
- """
-
def afterTraversal(request, ob):
- """
- Post-traversal hook.
+ """Post-traversal hook.
"""
def callObject(request, ob):
- """
- Calls the object, returning the result as a string.
+ """Call the object, returning the result.
+
For GET/POST this means calling it, but for other methods
(including those of WebDAV and FTP) this might mean invoking
a method of an adapter.
"""
def afterCall(request):
- """
- Post-callObject hook (if it was successful).
+ """Post-callObject hook (if it was successful).
"""
def handleException(request, exc_info, retry_allowed=1):
- """
+ """Handle an exception
+
Either:
- - sets the body of request.getResponse(),
+ - sets the body of the response, request.getResponse(), or
- raises a Retry exception, or
- throws another exception, which is a Bad Thing.
+
+ Note that this method should not leak, which means that
+ exc_info must be set to some other value before exiting the method.
"""
=== Zope3/lib/python/Zope/Publisher/IPublicationRequest.py 1.1.2.1 => 1.1.2.1.2.1 ===
"""
-from Interface import Interface
+from Zope.ComponentArchitecture.IViewService import IViewRequest
-class IPublicationRequest(Interface):
+class IPublicationRequest(IViewRequest):
"""Interface provided by requests to IPublication objects
"""
+ def getResponse():
+ """Return the request's response object
+
+ Return an IPublisherResponse for the request.
+ """
+
+ def close():
+ """Release resources held by the request.
+ """
+
def hold(object):
"""Hold a reference to an object until the request is closed
"""
@@ -44,3 +54,10 @@
"""Return the positional arguments given to the request.
"""
+ def setViewSkin(skin):
+ """Set the skin to be used for the request.
+
+ It's up to the publication object to decide this.
+ """
+
+
=== Zope3/lib/python/Zope/Publisher/IPublisherRequest.py 1.1.2.1 => 1.1.2.1.2.1 ===
"""
-from Interface import Interface
+from IPublicationRequest import IPublicationRequest
-class IPublisherRequest(Interface):
- """Interface used by the publsher
+class IPublisherRequest(IPublicationRequest):
+ """Request interface use by the publisher
+
+ The responsability of requests is to encapsulate protocol
+ specific details, especially wrt request inputs.
+
+ Request objects also serve as "context" objects. providing
+ construction of and access to responses and storage of publication
+ objects.
+
"""
- def supports_retry():
+ def supportsRetry():
"""Check whether the request supports retry
Return a boolean value indicating whether the request can be retried.
@@ -42,13 +50,11 @@
application-specific functionality hooks.
"""
- def getResponse():
- """Return the request's response object
-
- Return an IPublisherResponse for the request.
+ def setPublication(publication):
+ """Set the requets's publication object
"""
- def traverse(publication, object):
+ def traverse(object):
"""Traverse from the given object to the published object
The published object is returned.
@@ -60,10 +66,6 @@
- traverseName to actually do a single traversal
- """
-
- def close():
- """Release resources held by the request.
"""
def processInputs():
=== Zope3/lib/python/Zope/Publisher/IPublisherResponse.py 1.1.2.1 => 1.1.2.1.2.1 ===
def handleException(exc_info):
"""Handle an otherwise unhandled exception.
+
+ The handling of the exception is expected to effect the reponse body.
"""
+ # XXX ZopePublication seems to call this, so maybe this should be
+ # in an IPublicationResponse interface, but maybe this will change,
+ # so we'll apply YAGNI for now.
def outputBody():
"""Output the response to the client
"""
+ def retry():
+ """Return a retry response
+
+ Return a response suitable for repeating the publication attempt.
+ """
=== Zope3/lib/python/Zope/Publisher/Publish.py 1.1.2.13.6.1 => 1.1.2.13.6.2 ===
- Some other exception if handleException() raised an exception.
"""
- publication = None
+
+ publication = request.getPublication()
response = request.getResponse()
try:
request.processInputs()
- publication = request.getPublication()
publication.beforeTraversal(request)
root_object = publication.getApplication(request)
- object = request.traverse(publication, root_object)
+ object = request.traverse(root_object)
publication.afterTraversal(request, object)
result = publication.callObject(request, object)
@@ -41,16 +41,7 @@
publication.afterCall(request)
except:
- handleException(request, publication, sys.exc_info(), 1)
-
-
-
-def handleException(request, publication, exc_info, allow_retry=1):
- if publication is not None:
- publication.handleException(request, exc_info, allow_retry)
- else:
- request.getResponse().handleException(exc_info)
-
+ publication.handleException(request, sys.exc_info(), 1)
def publish(request):
@@ -62,8 +53,8 @@
executeRequest(request)
# Successful.
break
- except Retry, v:
- if request.supports_retry():
+ except Retry, retryException:
+ if request.supportsRetry():
# Create a copy of the request and use it.
newrequest = request.retry()
request.close()
@@ -71,8 +62,8 @@
else:
# Output the original exception.
publication = request.getPublication()
- handleException(request, publication,
- v.getOriginalException(), 0)
+ publication.handleException(
+ request, retryException.getOriginalException(), 0)
break
except:
# Bad exception handler or retry method.