Skip to content

Commit

Permalink
Run in thread to allow GUI to respond but disable run button
Browse files Browse the repository at this point in the history
  • Loading branch information
mcraig-ibme committed Mar 19, 2018
1 parent 35b48ab commit 1fe67e2
Showing 1 changed file with 59 additions and 36 deletions.
95 changes: 59 additions & 36 deletions python/asl/gui/run_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,65 +5,76 @@
import shutil
import shlex
import subprocess
from threading import Thread

import nibabel as nib

import wx
from wx.lib.pubsub import pub

class OptionError(RuntimeError):
pass

class Cmd():
class Mkdir:
def __init__(self, dirname):
self.dirname = dirname

def run(self):
if not os.path.exists(self.dirname):
os.makedirs(self.dirname)
return 0

class FslCmd:
def __init__(self, cmd):
self.cmd = cmd
script_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
fsldevdir = os.path.join(os.environ.get("FSLDEVDIR", ""), "bin")
fsldir = os.path.join(os.environ.get("FSLDIR", ""), "bin")

self.cmd = cmd
for d in (script_dir, fsldevdir, fsldir):
if os.path.exists(os.path.join(d, cmd)):
self.cmd = os.path.join(d, cmd)
break

def add(self, opt, val=None):
if val is not None:
self.cmd += " %s=%s" % (opt, str(val))
else:
self.cmd += " %s" % opt

def write_output(self, line, out_widget=None, out_stream=None):
if out_widget is not None:
out_widget.AppendText(line)
wx.Yield()
if out_stream is not None:
out_stream.write(line)
def write_output(self, line):
wx.CallAfter(pub.sendMessage, "run_stdout", line=line)

def run(self, out_widget=None, out_stream=None):
self.write_output(self.cmd, out_widget, out_stream)
def run(self):
self.write_output(self.cmd + "\n")
args = shlex.split(self.cmd)
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while 1:
retcode = p.poll() #returns None while subprocess is running
print("polled, retcode=", retcode)
line = p.stdout.readline()
self.write_output(line, out_widget, out_stream)
self.write_output(line)
if retcode is not None: break
self.write_output("\nReturn code: %i\n" % retcode, out_widget, out_stream)

self.write_output("\nReturn code: %i\n\n" % retcode)
return retcode

def __str__(self): return self.cmd

class FslCmd(Cmd):
"""
An FSL command
This will look for the executable in the same directory as the
GUI script first, then look in $FSLDEVDIR/bin, then $FSLDIR/bin. This is to enable
distribution of updated code as a bundle which can be run in-situ without installation
"""
def __init__(self, cmd):
script_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
fsldevdir = os.path.join(os.environ.get("FSLDEVDIR", ""), "bin")
fsldir = os.path.join(os.environ.get("FSLDIR", ""), "bin")
class CmdRunner(Thread):
def __init__(self, cmds, done_cb):
Thread.__init__(self)
self.cmds = cmds
self.done_cb = done_cb

self.cmd = cmd
for d in (script_dir, fsldevdir, fsldir):
if os.path.exists(os.path.join(d, cmd)):
self.cmd = os.path.join(d, cmd)
break
def run(self):
ret = -1
try:
for cmd in self.cmds:
ret = -1
ret = cmd.run()
if ret != 0:
break
finally:
self.done_cb(ret)

class AslRun(wx.Frame):
"""
Expand All @@ -89,6 +100,7 @@ def __init__(self, parent, run_btn, run_label):
self.run_btn = run_btn
self.run_btn.Bind(wx.EVT_BUTTON, self.dorun)
self.run_label = run_label
self.preview_data = None

self.sizer = wx.BoxSizer(wx.VERTICAL)
self.output_text = wx.TextCtrl(self, style=wx.TE_READONLY | wx.TE_MULTILINE)
Expand All @@ -98,20 +110,31 @@ def __init__(self, parent, run_btn, run_label):

self.SetSizer(self.sizer)
self.Bind(wx.EVT_CLOSE, self.close)
pub.subscribe(self.write_output, "run_stdout")

def write_output(self, line):
self.output_text.AppendText(line)

def close(self, _):
self.Hide()

def finished(self, retcode):
if retcode != 0:
self.write_output("\nWARNING: command failed\n")
self.update()

def dorun(self, _):
if self.run_seq:
self.Show()
self.Raise()
self.output_text.Clear()
for cmd in self.run_seq:
cmd.run(out_widget=self.output_text)
self.output_text.AppendText("\n")
self.run_btn.Enable(False)
self.run_label.SetForegroundColour(wx.Colour(0, 0, 128))
self.run_label.SetLabel("Running - Please Wait")
runner = CmdRunner(self.run_seq, self.finished)
runner.start()

def update(self, _):
def update(self):
"""
Get the sequence of commands and enable the run button if options are valid. Otherwise
display the first error in the status label
Expand Down Expand Up @@ -212,7 +235,7 @@ def get_run_sequence(self):
outdir = self.analysis.outdir()
if os.path.exists(outdir) and not os.path.isdir(outdir):
raise OptionError("Output directory already exists and is a file")
run.append(Cmd("mkdir %s" % outdir))
run.append(Mkdir(outdir))

# Input data
cmd = FslCmd("oxford_asl")
Expand Down

0 comments on commit 1fe67e2

Please sign in to comment.