|
|
# encoding: utf-8
|
|
|
"""
|
|
|
Object for encapsulating process execution by using callbacks for stdout,
|
|
|
stderr and stdin.
|
|
|
"""
|
|
|
__docformat__ = "restructuredtext en"
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
# Copyright (C) 2008 The IPython Development Team
|
|
|
#
|
|
|
# Distributed under the terms of the BSD License. The full license is in
|
|
|
# the file COPYING, distributed as part of this software.
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
# Imports
|
|
|
#-------------------------------------------------------------------------------
|
|
|
from killableprocess import Popen, PIPE
|
|
|
from threading import Thread
|
|
|
from time import sleep
|
|
|
|
|
|
class PipedProcess(Thread):
|
|
|
""" Class that encapsulates process execution by using callbacks for
|
|
|
stdout, stderr and stdin, and providing a reliable way of
|
|
|
killing it.
|
|
|
"""
|
|
|
|
|
|
def __init__(self, command_string, out_callback,
|
|
|
end_callback=None,):
|
|
|
""" command_string: the command line executed to start the
|
|
|
process.
|
|
|
|
|
|
out_callback: the python callable called on stdout/stderr.
|
|
|
|
|
|
end_callback: an optional callable called when the process
|
|
|
finishes.
|
|
|
|
|
|
These callbacks are called from a different thread as the
|
|
|
thread from which is started.
|
|
|
"""
|
|
|
self.command_string = command_string
|
|
|
self.out_callback = out_callback
|
|
|
self.end_callback = end_callback
|
|
|
Thread.__init__(self)
|
|
|
|
|
|
|
|
|
def run(self):
|
|
|
""" Start the process and hook up the callbacks.
|
|
|
"""
|
|
|
process = Popen((self.command_string + ' 2>&1', ), shell=True,
|
|
|
universal_newlines=True,
|
|
|
stdout=PIPE, stdin=PIPE, )
|
|
|
self.process = process
|
|
|
while True:
|
|
|
out_char = process.stdout.read(1)
|
|
|
if out_char == '':
|
|
|
if process.poll() is not None:
|
|
|
# The process has finished
|
|
|
break
|
|
|
else:
|
|
|
# The process is not giving any interesting
|
|
|
# output. No use polling it immediatly.
|
|
|
sleep(0.1)
|
|
|
else:
|
|
|
self.out_callback(out_char)
|
|
|
|
|
|
if self.end_callback is not None:
|
|
|
self.end_callback()
|
|
|
|
|
|
|
|
|
|