From 083532d0e7bd10545893a5d1bb2aa5786e83cf5d 2010-07-13 21:39:18 From: epatters Date: 2010-07-13 21:39:18 Subject: [PATCH] Initial checkin of Qt kernel manager. Began refactor of FrontendWidget. --- diff --git a/IPython/frontend/qt/console/frontend_widget.py b/IPython/frontend/qt/console/frontend_widget.py index 848100f..6ee43f5 100644 --- a/IPython/frontend/qt/console/frontend_widget.py +++ b/IPython/frontend/qt/console/frontend_widget.py @@ -5,11 +5,13 @@ import time import types # System library imports -from IPython.zmq.session import Message, Session from pygments.lexers import PythonLexer from PyQt4 import QtCore, QtGui import zmq +# IPython imports. +from IPython.zmq.session import Message, Session + # Local imports from call_tip_widget import CallTipWidget from completion_lexer import CompletionLexer @@ -100,23 +102,18 @@ class FrontendWidget(HistoryConsoleWidget): # 'QWidget' interface #--------------------------------------------------------------------------- - def __init__(self, parent=None, session=None, request_socket=None, - sub_socket=None): + def __init__(self, kernel_manager, parent=None): super(FrontendWidget, self).__init__(parent) - self.continuation_prompt = '... ' self._call_tip_widget = CallTipWidget(self) self._compile = CommandCompiler() self._completion_lexer = CompletionLexer(PythonLexer()) self._highlighter = FrontendHighlighter(self) - self.session = Session() if session is None else session - self.request_socket = request_socket - self.sub_socket = sub_socket - self.document().contentsChange.connect(self._document_contents_change) - self._kernel_connected() # XXX + self.continuation_prompt = '... ' + self.kernel_manager = kernel_manager def focusOutEvent(self, event): """ Reimplemented to hide calltips. @@ -216,6 +213,20 @@ class FrontendWidget(HistoryConsoleWidget): """ self.execute_source('run %s' % path, hidden=hidden) + def _get_kernel_manager(self): + """ Returns the current kernel manager. + """ + return self._kernel_manager + + def _set_kernel_manager(self, kernel_manager): + """ Sets a new kernel manager, configuring its channels as necessary. + """ + self._kernel_manager = kernel_manager + self._sub_channel = kernel_manager.get_sub_channel() + self._xreq_channel = kernel_manager.get_xreq_channel() + + kernel_manager = property(_get_kernel_manager, _set_kernel_manager) + #--------------------------------------------------------------------------- # 'FrontendWidget' protected interface #--------------------------------------------------------------------------- diff --git a/IPython/frontend/qt/kernelmanager.py b/IPython/frontend/qt/kernelmanager.py new file mode 100644 index 0000000..8868f55 --- /dev/null +++ b/IPython/frontend/qt/kernelmanager.py @@ -0,0 +1,79 @@ +""" A KernelManager that provides channels that use signals and slots. +""" + +# System library imports. +from PyQt4 import QtCore + +# IPython imports. +from IPython.zmq.kernel_manager import KernelManager, SubSocketChannel, \ + XReqSocketChannel, RepSocketChannel + + +class QtKernelManager(KernelManager): + """ A KernelManager that provides channels that use signals and slots. + """ + + sub_channel_class = QtSubSocketChannel + xreq_channel_class = QtXReqSocketChannel + rep_channel_class = QtRepSocketChannel + + +class QtSubSocketChannel(SubSocketChannel, QtCore.QObject): + + # Emitted when any message is received. + message_received = QtCore.pyqtSignal(dict) + + # Emitted when a message of type 'pyout' or 'stdout' is received. + output_received = QtCore.pyqtSignal(dict) + + # Emitted when a message of type 'pyerr' or 'stderr' is received. + error_received = QtCore.pyqtSignal(dict) + + #--------------------------------------------------------------------------- + # 'SubSocketChannel' interface + #--------------------------------------------------------------------------- + + def call_handlers(self, msg): + """ Reimplemented to emit signals instead of making callbacks. + """ + # Emit the generic signal. + self.message_received.emit(msg) + + # Emit signals for specialized message types. + msg_type = msg['msg_type'] + if msg_type in ('pyout', 'stdout'): + self.output_received.emit(msg) + elif msg_type in ('pyerr', 'stderr'): + self.error_received.emit(msg) + + +class QtXReqSocketChannel(XReqSocketChannel, QtCore.QObject): + + # Emitted when any message is received. + message_received = QtCore.pyqtSignal(dict) + + # Emitted when a reply has been received for the corresponding request type. + execute_reply = QtCore.pyqtSignal(dict) + complete_reply = QtCore.pyqtSignal(dict) + object_info_reply = QtCore.pyqtSignal(dict) + + #--------------------------------------------------------------------------- + # 'XReqSocketChannel' interface + #--------------------------------------------------------------------------- + + def call_handlers(self, msg): + """ Reimplemented to emit signals instead of making callbacks. + """ + # Emit the generic signal. + self.message_received.emit(msg) + + # Emit signals for specialized message types. + msg_type = msg['msg_type'] + signal = getattr(self, msg_type, None) + if signal: + signal.emit(msg) + + +class QtRepSocketChannel(RepSocketChannel, QtCore.QObject): + + pass diff --git a/IPython/zmq/kernelmanager.py b/IPython/zmq/kernelmanager.py index 5dad5c0..2308c92 100644 --- a/IPython/zmq/kernelmanager.py +++ b/IPython/zmq/kernelmanager.py @@ -1,9 +1,6 @@ """Kernel frontend classes. -To do: - -1. Create custom channel subclasses for Qt. -2. Create logger to handle debugging and console messages. +TODO: Create logger to handle debugging and console messages. """ @@ -23,6 +20,10 @@ class MissingHandlerError(Exception): class KernelManager(object): + sub_channel_class = SubSocketChannel + xreq_channel_class = XReqSocketChannel + rep_channel_class = RepSocketChannel + def __init__(self, xreq_addr, sub_addr, rep_addr, context=None, session=None): self.context = zmq.Context() if context is None else context @@ -55,15 +56,16 @@ class KernelManager(object): def get_sub_channel(self): """Get the SUB socket channel object.""" - return SubSocketChannel(self.context, self.session, self.sub_addr) + return self.sub_channel_class(self.context, self.session, self.sub_addr) def get_xreq_channel(self): """Get the REQ socket channel object to make requests of the kernel.""" - return XReqSocketChannel(self.context, self.session, self.xreq_addr) + return self.xreq_channel_class(self.context, self.session, + self.xreq_addr) def get_rep_channel(self): """Get the REP socket channel object to handle stdin (raw_input).""" - return RepSocketChannel(self.context, self.session, self.rep_addr) + return self.rep_channel_class(self.context, self.session, self.rep_addr) class ZmqSocketChannel(Thread): @@ -186,14 +188,7 @@ class XReqSocketChannel(ZmqSocketChannel): def _handle_recv(self): msg = self.socket.recv_json() - print "Got reply:", msg - try: - handler = self.handler_queue.get(False) - except Empty: - print "Message received with no handler!!!" - print msg - else: - self.call_handler(handler, msg) + self.call_handlers(msg) def _handle_send(self): try: @@ -222,13 +217,13 @@ class XReqSocketChannel(ZmqSocketChannel): def complete(self, text, line, block=None, callback=None): content = dict(text=text, line=line) msg = self.session.msg('complete_request', content) - return self._queue_request(msg, callback) + self._queue_request(msg, callback) return msg['header']['msg_id'] def object_info(self, oname, callback=None): content = dict(oname=oname) msg = self.session.msg('object_info_request', content) - return self._queue_request(msg, callback) + self._queue_request(msg, callback) return msg['header']['msg_id'] def _find_handler(self, name, callback): @@ -255,6 +250,15 @@ class XReqSocketChannel(ZmqSocketChannel): assert callable(func), "not a callable: %r" % func self._overriden_call_handler = func + def call_handlers(self, msg): + try: + handler = self.handler_queue.get(False) + except Empty: + print "Message received with no handler!!!" + print msg + else: + self.call_handler(handler, msg) + def call_handler(self, handler, msg): if self._overriden_call_handler is not None: self._overriden_call_handler(handler, msg)