[Checkins] SVN: Sandbox/shane/republish/zope Sketching ideas for publisher refactoring

Shane Hathaway shane at hathawaymix.org
Tue Feb 10 04:40:42 EST 2009


Log message for revision 96372:
  Sketching ideas for publisher refactoring
  

Changed:
  A   Sandbox/shane/republish/zope/
  A   Sandbox/shane/republish/zope/pipeline/
  A   Sandbox/shane/republish/zope/pipeline/caller.py
  A   Sandbox/shane/republish/zope/pipeline/complextraverser.py
  A   Sandbox/shane/republish/zope/pipeline/dbopener.py
  A   Sandbox/shane/republish/zope/pipeline/errorhandler.py
  A   Sandbox/shane/republish/zope/pipeline/requestcreator.py
  A   Sandbox/shane/republish/zope/pipeline/simpletraverser.py
  A   Sandbox/shane/republish/zope/pipeline/standard.py
  A   Sandbox/shane/republish/zope/pipeline/txncontroller.py
  A   Sandbox/shane/republish/zope/publisher/
  A   Sandbox/shane/republish/zope/publisher/interfaces/
  A   Sandbox/shane/republish/zope/publisher/interfaces/base.py
  A   Sandbox/shane/republish/zope/publisher/interfaces/browser.py
  A   Sandbox/shane/republish/zope/publisher/interfaces/complextraversal.py
  A   Sandbox/shane/republish/zope/publisher/interfaces/exceptions.py
  A   Sandbox/shane/republish/zope/publisher/interfaces/http.py
  A   Sandbox/shane/republish/zope.app.http/

-=-
Added: Sandbox/shane/republish/zope/pipeline/caller.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/caller.py	                        (rev 0)
+++ Sandbox/shane/republish/zope/pipeline/caller.py	2009-02-10 09:40:42 UTC (rev 96372)
@@ -0,0 +1,109 @@
+
+from zope.proxy import removeAllProxies
+
+class Caller(object):
+    """WSGI app that calls the traversed object.
+
+    Requires 'zope.request', which implements IRequest, in the environment.
+    """
+    def __call__(self, environ, start_response):
+        request = environ['zope.request']
+        name, ob = request.traversed[-1]
+        result = mapply(ob, request.getPositionalArguments(), request)
+        response = request.response
+        if result is not response:
+            response.setResult(result)
+        start_response(response.getStatusString(), response.getHeaders())
+        return response.consumeBodyIter()
+
+
+_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)


Property changes on: Sandbox/shane/republish/zope/pipeline/caller.py
___________________________________________________________________
Added: svn:mergeinfo
   + 


Property changes on: Sandbox/shane/republish/zope/pipeline/dbopener.py
___________________________________________________________________
Added: svn:mergeinfo
   + 


Property changes on: Sandbox/shane/republish/zope/pipeline/errorhandler.py
___________________________________________________________________
Added: svn:mergeinfo
   + 


Property changes on: Sandbox/shane/republish/zope/pipeline/requestcreator.py
___________________________________________________________________
Added: svn:mergeinfo
   + 

Added: Sandbox/shane/republish/zope/pipeline/simpletraverser.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/simpletraverser.py	                        (rev 0)
+++ Sandbox/shane/republish/zope/pipeline/simpletraverser.py	2009-02-10 09:40:42 UTC (rev 96372)
@@ -0,0 +1,11 @@
+
+
+
+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


Property changes on: Sandbox/shane/republish/zope/pipeline/simpletraverser.py
___________________________________________________________________
Added: svn:mergeinfo
   + 

Added: Sandbox/shane/republish/zope/pipeline/standard.py
===================================================================
--- Sandbox/shane/republish/zope/pipeline/standard.py	                        (rev 0)
+++ Sandbox/shane/republish/zope/pipeline/standard.py	2009-02-10 09:40:42 UTC (rev 96372)
@@ -0,0 +1,29 @@
+
+"""Creates a standard Zope WSGI publishing pipeline."""
+
+from zope.pipeline.call import Caller
+
+standard_pipeline = (
+    # RequestProfiler,
+    # CodeFreshnessChecker,
+    # Multiprocessor,
+    # ComponentConfigurator,
+    # DetailedTracebackGenerator,
+    RequestLogger,
+    RequestCreator,         # also sets locale (?)
+    DatabaseOpener,
+    TransactionController,  # includes retry logic and annotation
+    choose_traverser,       # complex or simple traversal based on zope.conf
+    AppErrorHandler,
+    Caller
+)
+
+def make_app(zope_conf, pipeline=standard_pipeline):
+    p = list(pipeline)
+    p.reverse()
+    factory = p.pop()
+    app = factory(zope_conf)
+    while p:
+        factory, kw = p.pop()
+        app = factory(app, zope_conf)
+    return app


Property changes on: Sandbox/shane/republish/zope/pipeline/txncontroller.py
___________________________________________________________________
Added: svn:mergeinfo
   + 

Added: Sandbox/shane/republish/zope/publisher/interfaces/base.py
===================================================================
--- Sandbox/shane/republish/zope/publisher/interfaces/base.py	                        (rev 0)
+++ Sandbox/shane/republish/zope/publisher/interfaces/base.py	2009-02-10 09:40:42 UTC (rev 96372)
@@ -0,0 +1,242 @@
+
+"""The base interfaces for request and response objects."""
+
+from zope.interface import Attribute
+from zope.interface import Interface
+from zope.interface.common.mapping import IExtendedReadMapping
+
+
+class IRequest(IExtendedReadMapping):
+    """Basic request data.
+
+    The request object may be used as a mapping object, in which case
+    values will be looked up in the order: [TODO].
+    """
+
+    environment = Attribute(
+        """Request environment data.
+
+        This is a pointer to the WSGI or CGI environment.
+        """)
+
+    traversal_path = Attribute(
+        """Sequence of steps to traverse, where each step is a unicode.
+        """)
+
+    traversed = Attribute(
+        """List of (name, obj) steps that were traversed.
+
+        The first object is the application root and has an empty name.
+        The last object is the object to call.
+        """)
+
+    response = Attribute(
+        """The request's IResponse object
+        """)
+
+    positional_args = Attribute(
+        """The positional arguments given to the request.
+        """)
+
+    principal = Attribute("""Principal object associated with the request.
+
+    It should be an IPrincipal wrapped in its AuthenticationService's context.
+    """)
+
+    bodyStream = Attribute(
+        """The stream that provides the data of the request.
+
+        The data returned by the stream will not include any possible header
+        information, which should have been stripped by the server (or
+        previous layer) before.
+
+        Also, the body stream might already be read and not return any
+        data. This is commonly done when retrieving the data for the ``body``
+        attribute.
+
+        If you access this stream directly to retrieve data, it will not be
+        possible by other parts of the framework to access the data of the
+        request via the ``body`` attribute.""")
+
+    debug = Attribute("""Debug flags (see IDebugFlags).""")
+
+    annotations = Attribute(
+        """Stores arbitrary application data under package-unique keys.
+
+        By "package-unique keys", we mean keys that are are unique by
+        virtue of including the dotted name of a package as a prefex.  A
+        package name is used to limit the authority for picking names for
+        a package to the people using that package.
+
+        For example, when implementing annotations for hypothetical
+        request-persistent adapters in a hypothetical zope.persistentadapter
+        package, the key would be (or at least begin with) the following::
+
+          "zope.persistentadapter"
+        """)
+
+    def hold(held):
+        """Hold a reference to an object until the request is closed.
+
+        The object should be an IHeld.  If it is an IHeld, its
+        release method will be called when it is released.
+        """
+
+    def close():
+        """Release resources held by the request.
+        """
+
+    def retry():
+        """Returns a re-initialized request to be retried.
+
+        Returns a request suitable for repeating the publication attempt,
+        or raises RetryNotSupported if the response can not be retried.
+        """
+
+
+class IResponse(Interface):
+    """Holds a response result."""
+
+    def getStatus():
+        """Returns the current status code as an integer.
+        """
+
+    def getStatusString():
+        """Return the status followed by the reason."""
+
+    def setStatus(status, reason=None):
+        """Sets the status code of the response
+
+        The status parameter must be either an integer (preferred)
+        or a value that can be converted to an integer using the int()
+        function,
+
+        The reason parameter is a short message to be sent with the status
+        code to the client.  If reason is not provided, a standard
+        reason will be supplied, falling back to "Unknown" for unregistered
+        status codes.
+        """
+
+    def setStandardStatus(name):
+        """Sets the status of the response using a standard status name.
+
+        The name will be converted to a code appropriate for the protocol.
+        For example, the name "NotFound" when applied to an HTTP
+        request will set the response status code to 404 and the name
+        "OK" will set the status to 200.
+
+        If the provided name is not recognized, the response status will
+        be set to a generic error status code (for example,
+        500 for HTTP).
+        """
+
+    def getHeaders():
+        """Returns a sequence of header name, value tuples.
+
+        If the protocol does not support headers, such as FTP, this
+        method should return an empty sequence.
+        """
+
+    def setResult(result):
+        """Sets response result value based on input.
+
+        Input is usually a unicode string, a string, None, or an object
+        that can be adapted to IResult with the request.  The end result
+        is an iterable such as WSGI prefers, determined by following the
+        process described below.
+
+        Try to adapt the given input, with the request, to IResult
+        (found elsewhere in this module).  If this fails, and the original
+        value was a string, use the string as the result; or if was
+        None, use an empty string as the result; and if it was anything
+        else, raise a TypeError.
+
+        If the result of the above (the adaptation or the default
+        handling of string and None) is unicode, encode it (to the
+        preferred encoding found by adapting the request to
+        zope.i18n.interfaces.IUserPreferredCharsets, usually implemented
+        by looking at the HTTP Accept-Charset header in the request, and
+        defaulting to utf-8) and set the proper encoding information on
+        the Content-Type header, if present.  Otherwise (the end result
+        was not unicode) application is responsible for setting
+        Content-Type header encoding value as necessary.
+
+        If the result of the above is a string, set the Content-Length
+        header, and make the string be the single member of an iterable
+        such as a tuple (to send large chunks over the wire; see
+        discussion in the IResult interface).  Otherwise (the end result
+        was not a string) application is responsible for setting
+        Content-Length header as necessary.
+
+        Set the result of all of the above as the response's result. If
+        the status has not been set, set it to an OK status (200 for HTTP).
+        """
+
+    def consumeBodyIter():
+        """Returns the response body as an iterable.
+
+        Note that this function can be only requested once, since it is
+        constructed from the result.
+        """
+
+    def retry():
+        """Returns a re-initialized response to be retried.
+
+        Returns a response suitable for repeating the publication attempt,
+        or raises RetryNotSupported if the response can not be retried.
+        """
+
+
+class IResult(Interface):
+    """An iterable that provides the body data of the response.
+
+    For simplicity, an adapter to this interface may in fact return any
+    iterable, without needing to strictly have the iterable provide
+    IResult.
+
+    IMPORTANT: The result object may be held indefinitely by a server
+    and may be accessed by arbitrary threads. For that reason the result
+    should not hold on to any application resources (i.e., should not
+    have a connection to the database) and should be prepared to be
+    invoked from any thread.
+
+    This iterable should generally be appropriate for WSGI iteration.
+
+    Each element of the iteration should generally be much larger than a
+    character or line; concrete advice on chunk size is hard to come by,
+    but a single chunk of even 100 or 200 K is probably fine.
+
+    If the IResult is a string, then, the default iteration of
+    per-character is wildly too small.  Because this is such a common
+    case, if a string is used as an IResult then this is special-cased
+    to simply convert to a tuple of one value, the string.
+
+    Adaptation to this interface provides the opportunity for efficient file
+    delivery, pipelining hooks, and more.
+    """
+
+    def __iter__():
+        """iterate over the values that should be returned as the result.
+
+        See IHTTPResponse.setResult.
+        """
+
+
+class IHeld(Interface):
+    """Object to be held and explicitly released by a request
+    """
+
+    def release():
+        """Release the held object
+
+        This is called by a request that holds the IHeld when the
+        request is closed
+
+        """
+
+class IDebugFlags(Interface):
+    """Features that support debugging."""
+
+    sourceAnnotations = Attribute("""Enable ZPT source annotations""")
+    showTAL = Attribute("""Leave TAL markup in rendered page templates""")
+

Added: Sandbox/shane/republish/zope/publisher/interfaces/browser.py
===================================================================
--- Sandbox/shane/republish/zope/publisher/interfaces/browser.py	                        (rev 0)
+++ Sandbox/shane/republish/zope/publisher/interfaces/browser.py	2009-02-10 09:40:42 UTC (rev 96372)
@@ -0,0 +1,24 @@
+
+
+
+class IBrowserRequest(IHTTPRequest):
+    """Browser-specific Request functionality.
+
+    Note that the browser is special in many ways, since it exposes
+    the Request object to the end-developer.
+    """
+
+class IBrowserSkinType(IInterface):
+    """A skin is a set of layers."""
+
+class IDefaultSkin(Interface):
+    """Any component providing this interface must be a skin.
+
+    This is a marker interface, so that we can register the default skin as an
+    adapter from the presentation type to `IDefaultSkin`.
+    """
+
+class ISkinChangedEvent(Interface):
+    """Event that gets triggered when the skin of a request is changed."""
+
+    request = Attribute("The request for which the skin was changed.")

Added: Sandbox/shane/republish/zope/publisher/interfaces/complextraversal.py
===================================================================
--- Sandbox/shane/republish/zope/publisher/interfaces/complextraversal.py	                        (rev 0)
+++ Sandbox/shane/republish/zope/publisher/interfaces/complextraversal.py	2009-02-10 09:40:42 UTC (rev 96372)
@@ -0,0 +1,56 @@
+
+
+class IPublishTraverse(Interface):
+
+    def publishTraverse(request, name):
+        """Lookup a name
+
+        The 'request' argument is the publisher request object.  The
+        'name' argument is the name that is to be looked up; it must
+        be an ASCII string or Unicode object.
+
+        If a lookup is not possible, raise a NotFound error.
+
+        This method should return an object having the specified name and
+        `self` as parent. The method can use the request to determine the
+        correct object.
+        """
+
+class IHTTPPublisher(IPublishTraverse):
+    """HTTP-specific publisher traversal"""
+
+class IBrowserPublisher(IPublishTraverse):
+
+    def browserDefault(request):
+        """Provide the default object
+
+        The default object is expressed as a (possibly different)
+        object and/or additional traversal steps.
+
+        Returns an object and a sequence of names.  If the sequence of
+        names is not empty, then a traversal step is made for each name.
+        After the publisher gets to the end of the sequence, it will
+        call browserDefault on the last traversed object.
+
+        Normal usage is to return self for object and a default view name.
+
+        The publisher calls this method at the end of each traversal path. If
+        a non-empty sequence of names is returned, the publisher will traverse
+        those names and call browserDefault again at the end.
+
+        Note that if additional traversal steps are indicated (via a
+        nonempty sequence of names), then the publisher will try to adjust
+        the base href.
+        """
+
+class IBrowserPage(IBrowserPublisher):
+    """Browser page"""
+
+    def __call__(*args, **kw):
+        """Compute a response body"""
+
+class IBrowserView(IView):
+    """Browser View"""
+
+class IDefaultBrowserLayer(IBrowserRequest):
+    """The default layer."""

Added: Sandbox/shane/republish/zope/publisher/interfaces/exceptions.py
===================================================================
--- Sandbox/shane/republish/zope/publisher/interfaces/exceptions.py	                        (rev 0)
+++ Sandbox/shane/republish/zope/publisher/interfaces/exceptions.py	2009-02-10 09:40:42 UTC (rev 96372)
@@ -0,0 +1,75 @@
+class IPublishingException(IException):
+    pass
+
+class PublishingException(Exception):
+    implements(IPublishingException)
+
+class ITraversalException(IPublishingException):
+    pass
+
+class TraversalException(PublishingException):
+    implements(ITraversalException)
+
+class INotFound(ILookupError, ITraversalException):
+    def getObject():
+        'Returns the object that was being traversed.'
+
+    def getName():
+        'Returns the name that was being traversed.'
+
+class NotFound(LookupError, TraversalException):
+    implements(INotFound)
+
+    def __init__(self, ob, name, request=None):
+        self.ob = ob
+        self.name = name
+
+    def getObject(self):
+        return self.ob
+
+    def getName(self):
+        return self.name
+
+    def __str__(self):
+        try:
+            ob = `self.ob`
+        except:
+            ob = 'unprintable object'
+        return 'Object: %s, name: %s' % (ob, `self.name`)
+
+class IDebugError(ITraversalException):
+    def getObject():
+        'Returns the object being traversed.'
+
+    def getMessage():
+        'Returns the debug message.'
+
+class DebugError(TraversalException):
+    implements(IDebugError)
+
+    def __init__(self, ob, message):
+        self.ob = ob
+        self.message = message
+
+    def getObject(self):
+        return self.ob
+
+    def getMessage(self):
+        return self.message
+
+    def __str__(self):
+        return self.message
+
+class IBadRequest(IPublishingException):
+    def __str__():
+        'Returns the error message.'
+
+class BadRequest(PublishingException):
+
+    implements(IBadRequest)
+
+    def __init__(self, message):
+        self.message = message
+
+    def __str__(self):
+        return self.message

Added: Sandbox/shane/republish/zope/publisher/interfaces/http.py
===================================================================
--- Sandbox/shane/republish/zope/publisher/interfaces/http.py	                        (rev 0)
+++ Sandbox/shane/republish/zope/publisher/interfaces/http.py	2009-02-10 09:40:42 UTC (rev 96372)
@@ -0,0 +1,207 @@
+
+
+
+class IRedirect(IPublishingException):
+    def getLocation():
+        'Returns the location.'
+
+class Redirect(PublishingException):
+
+    implements(IRedirect)
+
+    def __init__(self, location):
+        self.location = location
+
+    def getLocation(self):
+        return self.location
+
+    def __str__(self):
+        return 'Location: %s' % self.location
+
+
+class IMethodNotAllowed(IPublishingException):
+    """An exception that signals the 405 Method Not Allowed HTTP error"""
+
+    object = Attribute("""The object on which the error occurred""")
+
+    request = Attribute("""The request in which the error occurred""")
+
+
+class MethodNotAllowed(PublishingException):
+    """An exception that signals the 405 Method Not Allowed HTTP error"""
+
+    implements(IMethodNotAllowed)
+
+    def __init__(self, object, request):
+        self.object = object
+        self.request = request
+
+    def __str__(self):
+        return "%r, %r" % (self.object, self.request)
+
+
+class IHTTPRequest(IRequest):
+
+    method = Attribute("Request method, normalized to upper case")
+
+    path_suffix = Attribute(
+        """Additional traversal steps to be taken after all other traversal
+
+        This is used to handle HTTP request methods (except for GET
+        and POST in the case of browser requests) and XML-RPC methods.
+        """)
+
+    locale = Attribute(
+        """The locale object associated with this request.""")
+
+    form = Attribute(
+        """Form data
+
+        This is a read-only mapping from name to form value for the name.
+        """)
+
+    def getCookies():
+        """Return the cookie data
+
+        Data are returned as a mapping object, mapping cookie name to value.
+        """
+
+    cookies = Attribute(
+        """Request cookie data
+
+        This is a read-only mapping from variable name to value.
+        """)
+
+    def getHeader(name, default=None, literal=False):
+        """Get a header value
+
+        Return the named HTTP header, or an optional default
+        argument or None if the header is not found. Note that
+        both original and CGI-ified header names are recognized,
+        e.g. 'Content-Type', 'CONTENT_TYPE' and 'HTTP_CONTENT_TYPE'
+        should all return the Content-Type header, if available.
+
+        If the literal argument is passed, the header is searched
+        'as is', eg: only if the case matches.
+        """
+
+    headers = Attribute(
+        """Request header data
+
+        This is a read-only mapping from variable name to value.
+        It does *not* support iteration.
+        """)
+
+    URL = Attribute(
+        """Request URL data
+
+        When converted to a string, this gives the effective published URL.
+
+        This object can also be used as a mapping object. The key must
+        be an integer or a string that can be converted to an
+        integer. A non-negative integer returns a URL n steps from the
+        URL of the top-level application objects. A negative integer
+        gives a URL that is -n steps back from the effective URL.
+
+        For example, 'request.URL[-2]' is equivalent to the Zope 2
+        'request["URL2"]'. The notion is that this would be used in
+        path expressions, like 'request/URL/-2'.
+        """)
+
+
+    def getURL(level=0, path_only=False):
+        """Return the published URL with level names removed from the end.
+
+        If path_only is true, then only a path will be returned.
+        """
+
+    def getApplicationURL(depth=0, path_only=False):
+        """Return the application URL plus depth steps
+
+        If path_only is true, then only a path will be returned.
+        """
+
+    def getBasicAuth():
+        """Return (login, password) if there are basic credentials.
+
+        Return None if the request does not contain basic credentials.
+        """
+
+    _authUserPw = getBasicAuth
+
+    def unauthorized(challenge):
+        """Issue a 401 Unauthorized error (asking for login/password).
+
+        Sets the WWW-Authenticate header to the value of the
+        challenge parameter.
+        """
+
+
+class IHTTPResponse(IResponse):
+    """An object representation of an HTTP response."""
+
+    def setHeader(name, value, literal=False):
+        """Sets an HTTP return header "name" with value "value"
+
+        The previous value is cleared. If the literal flag is true,
+        the case of the header name is preserved, otherwise
+        word-capitalization will be performed on the header name on
+        output.
+        """
+
+    def addHeader(name, value):
+        """Add an HTTP Header
+
+        Sets a new HTTP return header with the given value, while retaining
+        any previously set headers with the same name.
+        """
+
+    def getHeader(name, default=None):
+        """Gets a header value
+
+        Returns the value associated with a HTTP return header, or
+        'default' if no such header has been set in the response
+        yet.
+        """
+
+    def appendToCookie(name, value):
+        """Append text to a cookie value
+
+        If a value for the cookie has previously been set, the new
+        value is appended to the old one separated by a colon.
+        """
+
+    def expireCookie(name, **kw):
+        """Causes an HTTP cookie to be removed from the browser
+
+        The response will include an HTTP header that will remove the cookie
+        corresponding to "name" on the client, if one exists. This is
+        accomplished by sending a new cookie with an expiration date
+        that has already passed. Note that some clients require a path
+        to be specified - this path must exactly match the path given
+        when creating the cookie. The path can be specified as a keyword
+        argument.
+        If the value of a keyword argument is None, it will be ignored.
+        """
+
+    def setCookie(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.
+        If the value of a keyword argument is None, it will be ignored.
+        """
+
+    def getCookie(name, default=None):
+        """Gets HTTP cookie data as a dict
+
+        Returns the dict of values associated with an HTTP cookie set in the
+        response, or 'default' if no such cookie has been set in the response
+        yet.
+        """
+
+    def redirect(location, status=302):
+        """Causes a redirection without raising an error.
+        """



More information about the Checkins mailing list