From d0e5fafc4041ff33f3e62679e3f5deef57687f5e 2010-08-20 20:30:09 From: epatters Date: 2010-08-20 20:30:09 Subject: [PATCH] * Refactored payload handling mechanism. * Paging is now integrated into the IPythonWidget. * The first cut at %edit support is now connected to the edit payload. This needs some more work. --- diff --git a/IPython/frontend/qt/console/frontend_widget.py b/IPython/frontend/qt/console/frontend_widget.py index ad21249..d039e27 100644 --- a/IPython/frontend/qt/console/frontend_widget.py +++ b/IPython/frontend/qt/console/frontend_widget.py @@ -339,9 +339,19 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin): def _process_execute_ok(self, msg): """ Process a reply for a successful execution equest. """ + payload = msg['content']['payload'] + for item in payload: + if not self._process_execute_payload(item): + warning = 'Received unknown payload of type %s\n' + self._append_plain_text(warning % repr(item['source'])) + + def _process_execute_payload(self, item): + """ Process a single payload item from the list of payload items in an + execution reply. Returns whether the payload was handled. + """ # The basic FrontendWidget doesn't handle payloads, as they are a # mechanism for going beyond the standard Python interpreter model. - pass + return False def _show_interpreter_prompt(self): """ Shows a prompt for the interpreter. diff --git a/IPython/frontend/qt/console/ipython_widget.py b/IPython/frontend/qt/console/ipython_widget.py index 2478b90..5689268 100644 --- a/IPython/frontend/qt/console/ipython_widget.py +++ b/IPython/frontend/qt/console/ipython_widget.py @@ -24,8 +24,8 @@ class IPythonWidget(FrontendWidget): """ # Signal emitted when an editor is needed for a file and the editor has been - # specified as 'custom'. - custom_edit_requested = QtCore.pyqtSignal(object) + # specified as 'custom'. See 'set_editor' for more information. + custom_edit_requested = QtCore.pyqtSignal(object, int) # The default stylesheet: black text on a white background. default_stylesheet = """ @@ -51,9 +51,13 @@ class IPythonWidget(FrontendWidget): in_prompt = 'In [%i]: ' out_prompt = 'Out[%i]: ' - # FrontendWidget protected class attributes. + # FrontendWidget protected class variables. #_input_splitter_class = IPythonInputSplitter + # IPythonWidget protected class variables. + _payload_source_edit = 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic' + _payload_source_page = 'IPython.zmq.page.page' + #--------------------------------------------------------------------------- # 'object' interface #--------------------------------------------------------------------------- @@ -116,6 +120,18 @@ class IPythonWidget(FrontendWidget): self._append_html(traceback) + def _process_execute_payload(self, item): + """ Reimplemented to handle %edit and paging payloads. + """ + if item['source'] == self._payload_source_edit: + self.edit(item['filename'], item['line_number']) + return True + elif item['source'] == self._payload_source_page: + self._page(item['data']) + return True + else: + return False + def _show_interpreter_prompt(self, number=None, input_sep='\n'): """ Reimplemented for IPython-style prompts. """ @@ -170,13 +186,16 @@ class IPythonWidget(FrontendWidget): # 'IPythonWidget' interface #--------------------------------------------------------------------------- - def edit(self, filename): + def edit(self, filename, line=None): """ Opens a Python script for editing. Parameters: ----------- filename : str A path to a local system file. + + line : int, optional + A line of interest in the file. Raises: ------- @@ -189,7 +208,7 @@ class IPythonWidget(FrontendWidget): message = 'Failed to open %s with the default application' raise OSError(message % repr(filename)) elif self._editor is None: - self.custom_edit_requested.emit(filename) + self.custom_edit_requested.emit(filename, line) else: Popen(self._editor + [filename]) @@ -211,8 +230,8 @@ class IPythonWidget(FrontendWidget): This parameter also takes two special values: 'default' : Files will be edited with the system default application for Python files. - 'custom' : Emit a 'custom_edit_requested(str)' signal instead - of opening an editor. + 'custom' : Emit a 'custom_edit_requested(str, int)' signal + instead of opening an editor. """ if editor == 'default': self._editor = 'default' diff --git a/IPython/frontend/qt/console/rich_ipython_widget.py b/IPython/frontend/qt/console/rich_ipython_widget.py index 66a5e68..c38946c 100644 --- a/IPython/frontend/qt/console/rich_ipython_widget.py +++ b/IPython/frontend/qt/console/rich_ipython_widget.py @@ -14,7 +14,8 @@ class RichIPythonWidget(IPythonWidget): text version. """ - # Protected class variables. + # RichIPythonWidget protected class variables. + _payload_source_plot = 'IPython.zmq.pylab.backend_payload.add_plot_payload' _svg_text_format_property = 1 #--------------------------------------------------------------------------- @@ -58,55 +59,29 @@ class RichIPythonWidget(IPythonWidget): # 'FrontendWidget' protected interface #--------------------------------------------------------------------------- - def _process_execute_ok(self, msg): + def _process_execute_payload(self, item): """ Reimplemented to handle matplotlib plot payloads. """ - payload = msg['content']['payload'] - for item in payload: - if item['source'] == 'IPython.zmq.pylab.backend_payload.add_plot_payload': - if item['format'] == 'svg': - svg = item['data'] - try: - image = svg_to_image(svg) - except ValueError: - self._append_plain_text('Received invalid plot data.') - else: - format = self._add_image(image) - format.setProperty(self._svg_text_format_property, svg) - cursor = self._get_end_cursor() - cursor.insertBlock() - cursor.insertImage(format) - cursor.insertBlock() + if item['source'] == self._payload_source_plot: + if item['format'] == 'svg': + svg = item['data'] + try: + image = svg_to_image(svg) + except ValueError: + self._append_plain_text('Received invalid plot data.') else: - # Add other plot formats here! - pass - elif item['source'] == 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic': - # TODO: I have implmented the logic for TextMate on the Mac. - # But, we need to allow payload handlers on the non-rich - # text IPython widget as well. Furthermore, we should probably - # move these handlers to separate methods. But, we need to - # be very careful to process the payload list in order. Thus, - # we will probably need a _handle_payload method of the - # base class that dispatches to the separate handler methods - # for each payload source. If a particular subclass doesn't - # have a handler for a payload source, it should at least - # print a nice message. - filename = item['filename'] - line_number = item['line_number'] - if line_number is None: - cmd = 'mate %s' % filename - else: - cmd = 'mate -l %s %s' % (line_number, filename) - os.system(cmd) - elif item['source'] == 'IPython.zmq.page.page': - # TODO: This is probably a good place to start, but Evan can - # add better paging capabilities. - self._append_plain_text(item['data']) + format = self._add_image(image) + format.setProperty(self._svg_text_format_property, svg) + cursor = self._get_end_cursor() + cursor.insertBlock() + cursor.insertImage(format) + cursor.insertBlock() + return True else: - # Add other payload types here! - pass + # Add other plot formats here! + return False else: - super(RichIPythonWidget, self)._process_execute_ok(msg) + return super(RichIPythonWidget, self)._process_execute_ok(msg) #--------------------------------------------------------------------------- # 'RichIPythonWidget' protected interface