################################################## # 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()