diff --git a/MantidPlot/ipython_widget/mantid_ipython_widget.py b/MantidPlot/ipython_widget/mantid_ipython_widget.py index bd3b4d3073bf669e541d7213a7d77174ef25127f..74e588cf42401477fe76c9146c7a8fc28bbcbe5c 100644 --- a/MantidPlot/ipython_widget/mantid_ipython_widget.py +++ b/MantidPlot/ipython_widget/mantid_ipython_widget.py @@ -7,11 +7,10 @@ from __future__ import (absolute_import, division, print_function) -import inspect import threading import types import warnings - +from mantid.py3compat import getfullargspec from PyQt4 import QtGui # IPython monkey patches the pygments.lexer.RegexLexer.get_tokens_unprocessed method @@ -36,7 +35,8 @@ except ImportError: from IPython.qt.console.rich_ipython_widget import RichIPythonWidget from IPython.qt.inprocess import QtInProcessKernelManager -def our_run_code(self, code_obj, result=None): + +def our_run_code(self, code_obj, result=None, async_=False): """ Method with which we replace the run_code method of IPython's InteractiveShell class. It calls the original method (renamed to ipython_run_code) on a separate thread so that we can avoid locking up the whole of MantidPlot while a command runs. @@ -47,18 +47,20 @@ def our_run_code(self, code_obj, result=None): A compiled code object, to be executed result : ExecutionResult, optional An object to store exceptions that occur during execution. + async_ : Bool (Experimental)) + Attempt to run top-level asynchronous code in a default loop. Returns ------- False : Always, as it doesn't seem to matter. """ - - t = threading.Thread() - #ipython 3.0 introduces a third argument named result - nargs = len(inspect.getargspec(self.ipython_run_code).args) - if (nargs == 3): - t = threading.Thread(target=self.ipython_run_code, args=[code_obj,result]) + # Different target arguments depending on IPython's version + if 'result' in getfullargspec(self.ipython_run_code).args: + if 'async_' in getfullargspec(self.ipython_run_code).kwonlyargs: + return self.ipython_run_code(code_obj, result, async_=async_) # return coroutine to be awaited + else: + t = threading.Thread(target=self.ipython_run_code, args=(code_obj, result)) else: - t = threading.Thread(target=self.ipython_run_code, args=[code_obj]) + t = threading.Thread(target=self.ipython_run_code, args=(code_obj,)) t.start() while t.is_alive(): QtGui.QApplication.processEvents() @@ -84,10 +86,10 @@ class MantidIPythonWidget(RichIPythonWidget): # Figure out the full path to the mantidplotrc.py file and then %run it from os import path - mantidplotpath = path.split(path.dirname(__file__))[0] # It's the directory above this one + mantidplotpath = path.split(path.dirname(__file__))[0] # It's the directory above this one mantidplotrc = path.join(mantidplotpath, 'mantidplotrc.py') shell = kernel.shell - shell.run_line_magic('run',mantidplotrc) + shell.run_line_magic('run', mantidplotrc) # These 3 lines replace the run_code method of IPython's InteractiveShell class (of which the # shell variable is a derived instance) with our method defined above. The original method diff --git a/qt/python/mantidqt/widgets/jupyterconsole.py b/qt/python/mantidqt/widgets/jupyterconsole.py index 8368014924bfcc8b030d49c712fb40357d7e21c1..5aaeeac67aafbc16ebb2f56841ec37c84ed430e6 100644 --- a/qt/python/mantidqt/widgets/jupyterconsole.py +++ b/qt/python/mantidqt/widgets/jupyterconsole.py @@ -71,17 +71,30 @@ def async_wrapper(orig_run_code, shell_instance): :param shell_instance: The shell instance associated with the orig_run_code :return: A new method that can be attached to shell_instance """ - def async_run_code(self, code_obj, result=None): + def async_run_code(self, code_obj, result=None, async_=False): """A monkey-patched replacement for the InteractiveShell.run_code method. It runs the in a separate thread and calls QApplication.processEvents - periodically until the method finishes + periodically until the method finishes. + + :param code_obj : code object + A compiled code object, to be executed + :param result : ExecutionResult, optional + An object to store exceptions that occur during execution. + :param async_ : Bool (Experimental)) + Attempt to run top-level asynchronous code in a default loop. + + :returns: An AsyncTaskResult object """ - # ipython 3.0 introduces a third argument named result - if len(getfullargspec(orig_run_code).args) == 3: - args = (code_obj, result) + # Different target arguments depending on IPython's version + if 'result' in getfullargspec(orig_run_code).args: + if 'async_' in getfullargspec(orig_run_code).kwonlyargs: + return orig_run_code(code_obj, result, async_=async_) # return coroutine to be awaited + else: + task = BlockingAsyncTaskWithCallback(target=orig_run_code, args=(code_obj, result), + blocking_cb=QApplication.processEvents) else: - args = (code_obj,) - task = BlockingAsyncTaskWithCallback(target=orig_run_code, args=args, blocking_cb=QApplication.processEvents) + task = BlockingAsyncTaskWithCallback(target=orig_run_code, args=(code_obj,), + blocking_cb=QApplication.processEvents) return task.start() return types.MethodType(async_run_code, shell_instance)