__all__ = ['ConsoleReactor'] import sys from netrepr import NetRepr, RemoteObjectPool, RemoteObjectReference from Foundation import * class ConsoleReactor(NSObject): def init(self): self = super(ConsoleReactor, self).init() self.pool = None self.netReprCenter = None self.connection = None self.commands = {} return self def connectionEstablished_(self, connection): #NSLog(u'connectionEstablished_') self.connection = connection self.pool = RemoteObjectPool(self.writeCode_) self.netReprCenter = NetRepr(self.pool) def connectionClosed_(self, connection): #NSLog(u'connectionClosed_') self.connection = None self.pool = None self.netReprCenter = None def writeCode_(self, code): #NSLog(u'writeCode_') self.connection.writeBytes_(repr(code) + '\n') def netEval_(self, s): #NSLog(u'netEval_') return eval(s, self.pool.namespace, self.pool.namespace) def lineReceived_fromConnection_(self, lineReceived, connection): #NSLog(u'lineReceived_fromConnection_') code = lineReceived.rstrip() if not code: return self.pool.push() command = map(self.netEval_, eval(code)) try: self.handleCommand_(command) finally: self.pool.pop() def handleCommand_(self, command): #NSLog(u'handleCommand_') basic = command[0] sel = 'handle%sCommand:' % (basic.capitalize()) cmd = command[1:] if not self.respondsToSelector_(sel): NSLog(u'%r does not respond to %r' % (self, command)) else: # XXX - this crashes PyObjC?? # self.performSelector_withObject_(sel, cmd) getattr(self, sel.replace(':', '_'))(cmd) def handleRespondCommand_(self, command): self.doCallback_sequence_args_( self.commands.pop(command[0]), command[0], map(self.netEval_, command[1:]), ) def sendResult_sequence_(self, rval, seq): nr = self.netReprCenter code = '__result__[%r] = %s' % (seq, nr.netrepr(rval)) self.writeCode_(code) def sendException_sequence_(self, e): nr = self.netReprCenter code = 'raise ' + nr.netrepr_exception(e) print "forwarding:", code self.writeCode_(code) def doCallback_sequence_args_(self, callback, seq, args): nr = self.netReprCenter try: rval = callback(*args) except Exception, e: self.sendException_sequence_(e, seq) else: self.sendResult_sequence_(rval, seq) def deferCallback_sequence_value_(self, callback, seq, value): self.commands[seq] = callback self.writeCode_('pipe.respond(%r, netrepr(%s))' % (seq, value)) def handleExpectCommand_(self, command): #NSLog(u'handleExpectCommand_') seq = command[0] name = command[1] args = command[2:] netrepr = self.netReprCenter.netrepr rval = None code = None if name == 'RemoteConsole.raw_input': self.doCallback_sequence_args_(raw_input, seq, args) elif name == 'RemoteConsole.write': self.doCallback_sequence_args_(sys.stdout.write, seq, args) elif name == 'RemoteConsole.displayhook': obj = args[0] def displayhook_respond(reprobject): print reprobject def displayhook_local(obj): if obj is not None: displayhook_respond(repr(obj)) if isinstance(obj, RemoteObjectReference): self.deferCallback_sequence_value_(displayhook_respond, seq, 'repr(%s)' % (netrepr(obj),)) else: self.doCallback_sequence_args_(displayhook_local, seq, args) elif name.startswith('RemoteFileLike.'): fh = getattr(sys, args[0]) meth = getattr(fh, name[len('RemoteFileLike.'):]) self.doCallback_sequence_args_(meth, seq, args[1:]) elif name == 'RemoteConsole.initialize': self.doCallback_sequence_args_(lambda *args:None, seq, args) else: self.doCallback_sequence_args_(NSLog, seq, [u'%r does not respond to expect %r' % (self, command,)]) def close(self): if self.connection is not None: self.writeCode_('raise SystemExit') self.pool = None self.netReprCenter = None self.connection = None self.commands = None