#!/usr/bin/python import code import optparse import os import sys import StringIO import traceback class EPython(object): def __init__(self, globals_, locals_): self.lines = [] self.globals = globals_ self.locals = locals_ def reset(self): self.lines = [] def prompt(self): if self.lines: return "PROMPT:..>" else: return "PROMPT:>>>" def handle(self, line): if line.startswith('ENTER:'): self.push(line[6:-1]) elif line.startswith('COMPLETE:'): self.complete(line[9:-1]) else: print "ERROR:invalid input" def complete(self, s): candidates = [] names = s.split('.') obj = None i = 0 name = names[0] if len(names) > 1: while i < len(names): name = names[i] if obj is None: if name in self.locals: obj = self.locals[name] elif name in self.globals: obj = self.globals[name] else: break else: if hasattr(obj, name): obj = getattr(obj, name) else: break i += 1 if i == len(names) - 1: base = '.'.join(names[:-1]) if base: base += '.' if obj is not None: newnames = dir(obj) else: newnames = set() newnames.update(dir(__builtins__)) newnames.update(self.locals) newnames.update(self.globals) candidates = [base + x for x in newnames if x.startswith(name)] print "COMPLETIONS:%s" % ('|'.join(candidates)) def push(self, s): self.lines.append(s) s2 = '\n'.join(self.lines) try: code_obj = code.compile_command(s2) if code_obj is None: return try: exec code_obj in self.globals, self.locals except Exception, e: print str(e) + "\n" + traceback.format_exc() except (SyntaxError, OverflowError, ValueError), e: print str(e) + "\n" + traceback.format_exc() self.reset() def main(self): while True: print '\n' + self.prompt() sys.stdout.flush() line = sys.stdin.readline() if not line: break self.handle(line) if __name__ == "__main__": stanzas = [] def add_eval(option, opt, value, parser): stanzas.append(('eval', value)) def add_path(option, opt, value, parser): stanzas.append(('path', value)) parser = optparse.OptionParser() parser.add_option('-e', '--eval', type='string', action='callback', callback=add_eval) parser.add_option('-r', '--run', type='string', action='callback', callback=add_path) parser.add_option('-p', '--pipe', action='store_true') parser.parse_args() del parser, add_path, add_eval __EP = EPython(globals_=globals(), locals_=locals()) sys.path.insert(0, os.getcwd()) for (type_, value) in stanzas: #break if type_ == 'eval': exec value in __EP.globals, __EP.locals __EP.push(value) elif type_ == 'path': f = open(value, 'r') exec f in __EP.globals, __EP.locals f.close() else: raise Exception, 'how can this happen?' del stanzas __EP.reset() __EP.main()