Sublime Forum

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

#1

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?

0 Likes

#2

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:

sublime.set_timeout(lambda: sublime.status_message("hello world"), 0)
0 Likes

#3

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?

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

Assuming:

    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:

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.

0 Likes

#4

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

		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…

0 Likes

#5

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. :open_mouth: Don’t ask.

Regarding my second question.

// 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)
0 Likes