Spawning subprocess with PyGTK using Twisted
Well, it is an age-old problem: How to schedule long-running tasks withing a GUI main loop (in our case PyGTK). There are a few ways:
Enter Twisted. We need to do two things with Twisted:
Ok, I did say it was pretty easy. Now all that you need to remember with this is that you should now run your main loop with reactor.run, and not gtk.main.
Now we should think about spawning our subprocess. We will do this by using reactor.spawnProcess, which looks like:
The only non-normal thing here is the processProtocol paramterer. All the other paramteres are standard things for things like subprocess.Popen. The processProtocol instance should be an instance of twisted.internet.protocol.ProcessProtocol, and defines how data is read from the pipes constructed to spawn the subprocess.
You can just use ProcessProtocol without overriding, but that will do nothing useful, not even print the results, so here is an example with our own ProcessProtocol class.
Now the subprocess will execute, and anything written to the child's stdout will be printed to the screen.
This may seem entirely unremarkable, but this is now ready to plug into a GUI. Since the callback outReceived is called inside the gtk main loop, it won't block and it will be called when necessary, so it may as well do something like:
Which would add the line to a textview control (called self.text_view).
Links:
Twisted How-to Processes
Twisted How-to PYGTK
- Use Python's subprocess module and select on the pipe with gobject's io_add_watch
- Use GTK's built in subprocess spawning abilities
- Use Twisted
Enter Twisted. We need to do two things with Twisted:
- Make sure Twisted knows we are running with PyGTK
- Launch the process
from twisted.internet import gtk2reactor
gtk2reactor.install()
from twisted.internet import reactor
Ok, I did say it was pretty easy. Now all that you need to remember with this is that you should now run your main loop with reactor.run, and not gtk.main.
Now we should think about spawning our subprocess. We will do this by using reactor.spawnProcess, which looks like:
twisted.internet.reactor.spawnProcess = spawnProcess(self,
processProtocol,
executable,
args=(),
env={},
path=None,
uid=None, gid=None, usePTY=0, childFDs=None
)
The only non-normal thing here is the processProtocol paramterer. All the other paramteres are standard things for things like subprocess.Popen. The processProtocol instance should be an instance of twisted.internet.protocol.ProcessProtocol, and defines how data is read from the pipes constructed to spawn the subprocess.
You can just use ProcessProtocol without overriding, but that will do nothing useful, not even print the results, so here is an example with our own ProcessProtocol class.
import os
# Have you remembered to install the gtk2reactor?
from twisted.internet import reactor
from twisted.internet.protocol import ProcessProtocol
class EchoingProcessProtocol(ProcessProtocol):
# Will get called when the subprocess has data on stdout
def outReceived(self, data):
print 'STDOUT:', data
# Will get called when the subprocess has data on stderr
def errReceived(self, data):
print 'STDERR:', data
# Will get called when the subprocess starts
def connectionMade(self):
print 'Started running subprocess'
# Will get called when the subprocess ends
def processEnded(self, reason):
print 'Completed running subprocess'
# Spawn the process and copy across the environment
reactor.spawnProcess(EchoingProcessProtocol(), 'ls', ['ls', '-al'], env=os.environ)
reactor.run()
Now the subprocess will execute, and anything written to the child's stdout will be printed to the screen.
This may seem entirely unremarkable, but this is now ready to plug into a GUI. Since the callback outReceived is called inside the gtk main loop, it won't block and it will be called when necessary, so it may as well do something like:
def outReceived(self, data):
self.text_view.get_buffer().insert(
self.text_view.get_buffer().get_end_iter(), data
)
Which would add the line to a textview control (called self.text_view).
Links:
Twisted How-to Processes
Twisted How-to PYGTK