[mod_python] Controlled output bufferring with psp

josh-modpython at valleyfree.com josh-modpython at valleyfree.com
Wed Nov 24 16:03:51 EST 2004


Hello folks

I'm new to mod_python (trying to migrate from php) and, being used to 
php, have liked php's output buffering features.

Specifically what I was looking for was a way to buffer all output and 
still control it (clear it inside an error handler, run it through a 
filter, etc.) Initially this is easy to acheive just using a StringIO 
object, but when I began using PSP I found this no longer worked, since 
PSP outputs to the request object directly, and once output is sent to 
the request object I saw no way to "take it back" or modify it.

So, for all the people in my boat, here is some code that will allow you 
do just that. This comes in very handy if you expect to have errors 
occur after or during a psp template is run, or if you want to do 
something like filter the final output.

I would appreciate it if any mod_python gurus could point out any 
pitfalls in this approach.

Thanks for any feedback, and I hope this helps a few people out there.  
(I assume this is kosher to post code straight to the list, if not 
please slap my hand and inform me of list protocol)

import sys
import cStringIO
import traceback
from mod_python import apache
from mod_python import psp

class bufferProxy:  
    """This proxy class is used to supply a write() method
    to replace req.write(), including the optional flush
    parameter, which is ignored and only present to prevent
    an exception being raised for its presence. If it
    weren't for the flush parameter, you wouldn't need this
    proxy class at all, you could just assign req.write to
    the StringIO object's write method."""
    
    def __init__(self,outputBuffer):
        self.outputBuffer = outputBuffer
        
    def write(self,data,flush=None):
        """Writes data to the output buffer. The flush
        argument is simply ignored; the buffer is only
        flushed at the end of the handler in the finally
        clause. Though, you could allow flushing by sending
        the contents of the buffer to the oldReqWrite
        method and then clearing it."""
        
        self.outputBuffer.write(data)

def handler(req):
    """A request handler that illustrates the use of a 
    StringIO output buffer instead of using the Apache 
    buffer normally written to by req.write, which allows 
    for simultaneous use of all of the following:
    
    1. print statements (redirecting sys.stdout)
    2. psp templates (that use req.write)
    3. error handlers that can erase/override/filter all 
    output even after it has been written to the buffer
    
    """
    
    req.content_type = "text/html"
    
    outputBuffer = cStringIO.StringIO()
    outputBufferProxy = bufferProxy(outputBuffer)
    
    oldStdout = sys.stdout
    oldReqWrite = req.write
    
    sys.stdout = outputBuffer
    req.write = outputBufferProxy.write
    
    try: # outer try block used for finally clause
        
        try: # inner block used for exception handling
            
            # this works
            print 'Hello world!<br>'
            
            # and this works
            req.write('Hello, again!<br>\n')
            
            # and PSP works, too, just put a real psp
            # template in there and uncomment it, of course
            # also placing any needed vars in run()...
            
            # template = psp.PSP(req, \
            #    filename='mytemplate.psp')
            # template.run()
            
            # raise and catch the an exception or do error
            # handling however you like...
            raise "some error"
            
        except:
            
            # on error, clear the buffer and show an error, 
            # do stuff, show a stack trace, etc, you can 
            # even show everything output up to this point:
            
            allOutputUpToNow = outputBuffer.getvalue()
            outputBuffer.seek(0)
            outputBuffer.truncate(0)
            print '<h1>An exception has occurred...</h1>'
            print '<pre>'
            traceback.print_exc(None,outputBuffer)
            print '</pre>'
            print '<hr>'
            print '<h2>Here is all the output up to the point' \
                ' of the exception:</h2>'
            print allOutputUpToNow
            # note that it would be a good idea to html 
            # entity quote the contents of allOutputUpToNow
            
    finally:
        
        # restore IO streams and send final output
        sys.stdout = oldStdout
        req.write = oldReqWrite
        req.write(outputBuffer.getvalue())
        outputBuffer.close()
        return apache.OK


More information about the Mod_python mailing list