################################################################################ # extra entry-points for App class tree ################################################################################ import sys, os, string from PP2E.System.App.Bases.app import * # use this file to get everything from PP2E.System.App.Kinds.internal import * # or import from specific module from PP2E.System.App.Kinds.interact import * from PP2E.System.App.Kinds.redirect import * ################################################################################ # Mix-in class examples: __init__ taken from RedirectInternalApp. # The result (stdout output string) is returned from App.main() call. # # Multiple-inheritance name resolution is depth-first, l-top-r. # We need InteractiveApp's run(), and RedirectInternalApp's __init__(), # so there's a problem with either: # # class TestInteractiveApp(RedirectInternalApp, InteractiveApp): # pass # wrong run! # # class TestInteractiveApp(InteractiveApp, RedirectInternalApp): # pass # wrong __init__! # # Two solutions are illustrated in the 2 mix-in classes here. # Note: this subclassing technique can be used to test any class # derived from App (pack, mtool..): inherit from the tested class # plus RedirectInternalApp, and resolve conflicts manually (or use # FuncTestApp below, on the top-level entry-point in the tree). # The "run =" is like "def run(self): InteractiveApp.run(self)" ################################################################################ class TestInteractiveApp(RedirectInternalApp, InteractiveApp): run = InteractiveApp.run class TestMenuApp(MenuDictApp, RedirectInternalApp): __init__ = RedirectInternalApp.__init__ stop = RedirectInternalApp.stop # resolve conflicts closeApp = RedirectInternalApp.closeApp # by manual assignment ################################################################################ # Top-level external entry points (non-oop) # # import app # from mtool2 import MtoolApp # app.appCall(MtoolApp, '-x', '-i', '/home/lutz/mbox', '-t', 'steve') # # import app # app.appRun('mtool2.py', '-i', '/home/lutz/mbox', '-f', 'andy', '-o', '-') # app.appRun('mtool2.py', '-i /home/lutz/mbox', '-f andy -o -') # # _buildArgs() flattens the arguments passed in, splits multi-arg # strings, and converts non-strings to strings. List/tuple trees # can be constructed and passed in-- flattened into a list of strings, # and/or args can be passed in as args to appCall (varargs); ################################################################################ def _buildArgs(args): res = [] for arg in args: if type(arg) in [type([]), type(())]: res = res + _buildArgs(arg) # ['a', '-b', (1, 2)] elif type(arg) != type(''): res.append(`arg`) # 1 2.2 else: res = res + string.split(arg) # "f1 f2 f3" return res def appCall(appClass, *args): # call an App like a function save_argv = sys.argv sys.argv = [appClass.__name__] + _buildArgs(args) result = appClass().main() sys.argv = save_argv return result def appRun(script, *args): # run as a new process arglist = _buildArgs(args) # or: ScriptOutput(s,a).read() cmdline = script + ' ' + string.join(arglist) return os.popen(cmdline, 'r').read() ################################################################################ # Treat an App run like a file. # Here, read/write mean the view outside an app, instead of the app itself # (not it's i/o streams). ScriptPipe.write() sends data to the app, and # ScriptPipe.read() gets the app's output. ################################################################################ class ScriptPipe: def __init__(self, cmdline, mode): self.pipe = os.popen(cmdline, mode) # closed on deletion def __getattr__(self, name): return getattr(self.pipe, name) # delegate to pipe file def cmdline(self, script, args): return script + ' ' + string.join(_buildArgs(args)) class ScriptOutput(ScriptPipe): # use .read, .readline(),... def __init__(self, script, *args): ScriptPipe.__init__(self.cmdline(script, args) + " -o -", 'r') class ScriptInput(ScriptPipe): # use .write(), .writelines(),... def __init__(self, script, *args): ScriptPipe.__init__(self.cmdline(script, args) + " -i -", 'w') ################################################################################ # Simple i/o redirection # Note: we can't rely on App.__del__ to restore streams when App.main() # returns: __del__ won't run if any ref's to the App instance remain. # (Example: if any get*() call fails, there's a traceback object with # a reference). Without App.closeApp, we'd have to call __del__ here. ################################################################################ def _redirected1(input, function, args): # the hard way... save_streams = sys.stdin, sys.stdout sys.stdin = Input(input) sys.stdout = Output() try: apply(function, args) except: sys.stderr.write('error in function! ') sys.stderr.write(`sys.exc_type` + ',' + `sys.exc_value` + '\n') result = sys.stdout.text sys.stdin, sys.stdout = save_streams return result class FuncTestApp(RedirectInternalApp): # the way of tao... def __init__(self, input, func, args): RedirectInternalApp.__init__(self, input) self.call = func, args def run(self): #try: apply(apply, self.call) #except: # self.message('error in function!' + `self.exception()`) def redirected(input, function, args): return FuncTestApp(input, function, args).main()