Home Download Buy Blog Forum Support

long-running subprocess.call() zombifies ST3--threading?

long-running subprocess.call() zombifies ST3--threading?

Postby rpardee on Thu Aug 08, 2013 10:40 pm

Hey All,

I continue to work on my custom build comand (a WindowCommand). Unfortunately, I'm finding that when I run my external process via subprocess.call(), the ST3 app stops updating the window--it's pretty much completely nonresponive until the external app finishes. That seems to be true of all ST3 instances--that is, if I have 3 projects open w/3 different ST3 windows, building one of them zombifies all 3 windows, which is a major bummer.

So I guess this means I need to run my external process in a newly-spawned thread--is that right? The behavior I'm looking for is:
  • user edits script
  • user builds--my WindowCommand runs & shells out to the external program
  • all instances of ST3 stay responsive while external program runs
  • external program ends--control returns to my WindowCommand, which trolls the external-process-created log file for errors/warnings, pops dialogs & opens various output files for inspection.
Unfortunately I'm a python noob (and have only unsuccessful attempts at multi-threading in other langs). So I don't want to go down this road if it can't work b/c of some quirk of the ST3 runtime environment, or won't give me the behavior I need. Can any kind soul out there tell me:
  • am I right that executing my external program on a python thread will give me the behavior I'm after?
  • can said threading work in the ST3 environment?
  • in figuring out how to do threading, am I okay just reading the raw python docs (e.g., http://docs.python.org/3/library/threading.html), or is there an ST3 API that I need to use?
Many thanks!

-Roy
rpardee
 
Posts: 28
Joined: Wed Jul 11, 2012 8:51 pm

Re: long-running subprocess.call() zombifies ST3--threading?

Postby adzenith on Fri Aug 09, 2013 2:16 pm

You can use sublime.set_async_timeout to run something in another thread -- you're free to pass a delay of 0.
adzenith
 
Posts: 1217
Joined: Mon Oct 19, 2009 9:12 pm

Re: long-running subprocess.call() zombifies ST3--threading?

Postby rpardee on Fri Aug 09, 2013 7:28 pm

Thanks so much for the reply--that method looks really promising! Unfortunately it's not proving as dead simple as I was hoping. If I sub out my actual build process for method that just shells out to calc.exe

Code: Select all
  def run_calc(self):
    # sublime.message_dialog("boobies!")
    subprocess.call('calc.exe')

ST3 stays nice and responsive while the calculator is running.

But when I copy/paste my actual code into something I can call with set_timeout_async, it works just the same as before--zombie city.

Is there something obvious I'm doing wrong?

Code: Select all
  def shell_out_to_sas(self, call_args, prg_filename, lst_filename, log_filename, err_regx, sas_path):
    subprocess.call(call_args)
    sublime.status_message("Finished running " + prg_filename)
    if os.path.exists(lst_filename):
      self.window.open_file(lst_filename)
    if os.path.exists(log_filename):
      res = "Finished!\n"
      for l in self.find_logs(log_filename):
        res += self.check_log(l, err_regx)
      sublime.message_dialog(res)
    else:
      sublime.message_dialog("Problem!  Did not find the expected log file (" + log_filename + ").")
    # print sas_path + " exists?: " + str(os.path.exists(sas_path))
    # sublime.message_dialog("Pretend I ran " + sas_path)
    # self.window.open_file(r'C:\Users\Roy\AppData\Roaming\Sublime Text 3\Packages\SAS\notes.txt')
   


  def run(self):
    self.window.active_view().run_command('save')
    prg_filename = self.window.active_view().file_name()
    extension = os.path.splitext(prg_filename)[-1].lower()
    if extension == '.sas':
      log_filename = prg_filename[:-3] + 'log'
      lst_filename = prg_filename[:-3] + 'lst'
      lrn_filename = lst_filename + '.last.run'
      if os.path.exists(lrn_filename):
        os.remove(lrn_filename)
      s = sublime.load_settings('sas.sublime-settings')
      sas_path = s.get('sas-path', "C:\\Program Files\\SAS\\SASFoundation\\9.2\\sas.exe")
      sas_args = s.get('sas-args', ['-nologo', '-noovp'])
      err_regx = s.get('err-regx', "(^(error|warning:)|uninitialized|[^l]remerge|Invalid data for)(?! (the .{4,15} product with which|your system is scheduled|will be expiring soon, and|this upcoming expiration.|information on your warning period.))")
      s.set('sas-path', sas_path)
      s.set('sas-args', sas_args)
      s.set('err-regx', err_regx)
      sublime.save_settings('sas.sublime-settings')
      err_regx = re.compile(err_regx, re.MULTILINE + re.IGNORECASE)
      if os.path.exists(sas_path):
        call_args = [sas_path, '-sysin', prg_filename, '-log', log_filename, '-print', lst_filename] + sas_args
        # print subprocess.list2cmdline(call_args)
        # sublime.set_timeout_async(self.run_calc, 0)
        sublime.set_timeout_async(self.shell_out_to_sas(call_args, prg_filename, lst_filename, log_filename, err_regx, sas_path), 0)
      else:
        sublime.message_dialog("Problem--could not find sas.exe at " + sas_path + ".  Please update the sas-path setting in sas.sublime-settings in the User package folder.")
    else:
      sublime.message_dialog('Sorry--this only works with .sas files.')


Thanks again!
rpardee
 
Posts: 28
Joined: Wed Jul 11, 2012 8:51 pm

Re: long-running subprocess.call() zombifies ST3--threading?

Postby sapphirehamster on Sat Aug 10, 2013 10:49 pm

In the following:
Code: Select all
sublime.set_timeout_async(self.shell_out_to_sas(call_args, prg_filename, lst_filename, log_filename, err_regx, sas_path), 0)

you need to pass a callback as the first argument. What you are doing is calling the function, and then using its return value (in this case None) as the parameter.

There are a variety of ways you could fix it. Perhaps the simplest is to stick a "lambda:" in front like this:
Code: Select all
sublime.set_timeout_async(lambda: self.shell_out_to_sas(call_args, prg_filename, lst_filename, log_filename, err_regx, sas_path), 0)
sapphirehamster
 
Posts: 90
Joined: Sun Jul 01, 2012 11:19 pm

Re: long-running subprocess.call() zombifies ST3--threading?

Postby rpardee on Mon Aug 12, 2013 2:15 pm

Genius! Thank you so much! Adding lambda: gives me just the behavior I wanted.
rpardee
 
Posts: 28
Joined: Wed Jul 11, 2012 8:51 pm


Return to Plugin Development

Who is online

Users browsing this forum: No registered users and 6 guests