Home Download Buy Blog Forum Support

Call a function with stdout/err from long-running process.

Call a function with stdout/err from long-running process.

Postby Xavura on Sat Jul 14, 2012 4:45 pm

I'd like to be able to call a function with the argument being stdout/err whenever there is stdout/err on a long-running process, so that I can then display it via a panel, or the status bar, or whatever depending on user options.

I asked in #python on IRC and someone said it's not really possible unless Sublime implements something (to do with file descriptors) in it's API, which I'm fairly sure it doesn't.

I know there are going to be other ways to achieve the same thing, perhaps something involving files, but I'd prefer this to be as clean as possible. Thoughts/ideas?
Xavura
 
Posts: 19
Joined: Sat Jul 14, 2012 4:40 pm

Re: Call a function with stdout/err from long-running process.

Postby quarnster on Sat Jul 14, 2012 5:01 pm

You can run whatever is taking time in a separate thread and just use "print" as normal to display the output in the python console. If you want to display it as a status message you can do something like this from the thread:

Code: Select all
sublime.set_timeout(lambda: sublime.status_message("hello world"), 0)
quarnster
 
Posts: 389
Joined: Tue Nov 29, 2011 11:34 am

Re: Call a function with stdout/err from long-running process.

Postby Xavura on Mon Jul 16, 2012 8:49 pm

I've been having problem after problem both trying to get this work cross-platform and also with threads.

Why would this fail (on Windows) from within a thread?

Code: Select all
      self.process = Popen([path.join(self.binaryDir, 'coffee'),
         '-c', '-b', '-w', '-o', libDir, srcDir],
         shell=False, stdout=PIPE, stderr=PIPE)


Assuming:
Code: Select all
    self.binaryDir = C:\Users\Joe\AppData\Roaming\npm\coffee
    libDir = C:\Users\Joe\Documents\GitHub\CoffeeScript-Sublime-Plugin\lib
    srcDir = C:\Users\Joe\Documents\GitHub\CoffeeScript-Sublime-Plugin\src


Error:
Code: Select all
Exception in thread Thread-3:
Traceback (most recent call last):
  File ".\threading.py", line 532, in __bootstrap_inner
  File ".\CoffeeScript.py", line 233, in run
  File ".\subprocess.py", line 633, in __init__
  File ".\subprocess.py", line 842, in _execute_child
WindowsError: [Error 2] The system cannot find the file specified


All of the files exist and I have also tried forward slashes (read that it may work, somewhere). Running the command being passed to Popen works as expected in cmd.

It would be nice if I could just use shell=True and use the system PATH but it's not possible in this context for whatever reason.

It would also be nice if I could just use which/where outside of the thread to determine the location of the binary automatically. This also is not possible.
Xavura
 
Posts: 19
Joined: Sat Jul 14, 2012 4:40 pm

Re: Call a function with stdout/err from long-running process.

Postby Xavura on Tue Jul 17, 2012 1:14 am

Well I got that part working but I'm having more problems. A console window is appearing, I've tried hiding with the following:

Code: Select all
      startupinfo = subprocess.STARTUPINFO()
      if IS_WINDOWS:
         # Use magic numbers because apparently sometimes subprocess doesn't have the constants we need.
         startupinfo.dwFlags |= 1
         startupinfo.wShowWindow = 0


And passing that into Popen but it does not get rid of the console window.

Also I am unable to terminate the process via popenobject.kill, nor os.kill nor os.terminate...
Xavura
 
Posts: 19
Joined: Sat Jul 14, 2012 4:40 pm

Re: Call a function with stdout/err from long-running process.

Postby Xavura on Wed Jul 18, 2012 9:09 am

In case anyone else ever has the same questions/problems and a search brings them here:

Regarding my first question, it does work. I didn't change anything and it started working on its own. :shock: Don't ask.

Regarding my second question.

Code: Select all
// This works (remove the /T if you don't want to kill the entire process tree):
import subprocess
subprocess.call(['taskkill', '/F', '/T', '/PID', str(pid)])

// This supposedly should work but I was having problems with it:
import ctypes
handle = ctypes.windll.kernel32.OpenProcess(1, False, pid)
ctypes.windll.kernel32.TerminateProcess(handle, -1)
ctypes.windll.kernel32.CloseHandle(handle)
Xavura
 
Posts: 19
Joined: Sat Jul 14, 2012 4:40 pm


Return to Plugin Development

Who is online

Users browsing this forum: Exabot [Bot], Yahoo [Bot] and 2 guests