##################################################
# SPYCE - Python-based HTML Scripting
# Copyright (c) 2002 Rimon Barr.
#
# Refer to spyce.py
# CVS: $Id: stdout.py 540 2005-04-08 20:58:32Z jbe $
##################################################
from spyceModule import spyceModule
from spyceUtil import NoCloseOut
from cStringIO import StringIO
__doc__ = '''Sets the thread-safe server stdout to the response object for
convenience of using print statements, and supports output redirection.'''
class stdout(spyceModule):
def start(self):
# output redirection stack
self.outputStack = []
# thread-safe stdout swap
self.stdout = self._api.getStdout()
self._api.setStdout(myResponseWrapper(self))
# memoize storage
try: self.memoizeCache = self._api.getServerObject().memoized
except AttributeError:
self.memoizeCache = self._api.getServerObject().memoized = {}
def finish(self, theError=None):
# close all redirects
while self.outputStack:
self.pop()
# thread-safe stdout swap back
self._api.setStdout(self.stdout)
def push(self, file=None):
'Redirect stdout to buffer'
old_response = self._api.getResponse()
old_response_mod = self._api.getModule('response')
new_response = spyceCaptureResponse(old_response)
self._api.setResponse(new_response)
new_response_mod = self._api.spyceModule('response', 'response.py')(self._api)
self._api.setModule('response', new_response_mod)
new_response_mod.start()
self.outputStack.append( (file, old_response, old_response_mod) )
def pop(self):
'Return buffer value, and possible write to file'
self._api.getModule('response').finish()
buffer = self._api.getResponse().getCapturedOutput()
file, old_response, old_response_mod = self.outputStack.pop()
self._api.setModule('response', old_response_mod)
self._api.setResponse(old_response)
if file:
file = os.path.join(os.path.dirname(self._api.getFilename()), file)
out = None
try:
out = open(file, 'w')
out.write(buffer)
finally:
if out: out.close()
return buffer
def capture(self, _spyceReserved, *args, **kwargs):
'Capture the output side-effects of a function'
f = _spyceReserved # placeholder not to collide with kwargs
self.push()
r = apply(f, args, kwargs)
s = self.pop()
return r, s
def __repr__(self):
if hasattr(self, 'outputStack'):
return 'stdout depth: %s' % len(self.outputStack)
else:
return 'stdout not started'
class myResponseWrapper:
def __init__(self, mod):
self._mod = mod
mod._api.registerModuleCallback(self.syncResponse)
self.syncResponse()
def syncResponse(self):
response = self._mod._api.getModule('response')
# functions (for performance)
self.write = response.write
self.writeln = response.writeln
self.flush = response.flush
def close(self):
raise 'method not allowed'
class spyceCaptureResponse:
"Capture output, and let everything else through."
def __init__(self, old_response):
self._old_response = old_response
self._buf = StringIO()
def write(self, s):
self._buf.write(s)
def close(self):
raise 'cannot close output while capturing output'
def clear(self):
self._buf = StringIO()
def sendHeaders(self):
raise 'cannot sendHeaders while capturing output!'
def flush(self, stopFlag=0):
pass
def unbuffer(self):
raise 'cannot unbuffer output while capturing output!'
def __getattr__(self, name):
return eval('self._old_response.%s'%name)
def getCapturedOutput(self):
return self._buf.getvalue()
|