Launching Sub-Processes

From IronPython Cookbook

Because the select module is not available, you can't use the subprocess module in IronPython. Luckily there is an easy to use (but not as elegant) alternative - System.Diagnostics.Process. (This entry written with help from a post by Steve Gilham.)

Launch a subprocess, using the static method Start:

from System.Diagnostics import Process

Process.Start('something.exe', 'args')

If you want stdout from the subprocess on your stdout, you have to jump through a few more hoops. The following example does this, plus waits for the subprocess to exit:

p = Process()
p.StartInfo.UseShellExecute = False
p.StartInfo.RedirectStandardOutput = True
p.StartInfo.FileName = 'python'
p.StartInfo.Arguments = 'somefile.py'
p.Start()
p.WaitForExit() 

If you want you can set environment variables for the subprocess:

proc = Process()
proc.StartInfo.FileName = gnuplotPath
proc.StartInfo.Arguments = '"%s"' % scriptPath
proc.StartInfo.EnvironmentVariables['GDFONTPATH'] = fontPath
proc.StartInfo.EnvironmentVariables['GNUPLOT_FONTPATH'] = fontPath
proc.StartInfo.UseShellExecute = False
proc.Start()
proc.WaitForExit()

Note: Please, be cautious about using process.OutputDataReceived event handlers. These don't handle binary subprocess output well, as the output is converted to Unicode before triggering the event. You might need to read directly from process.StandardOutput.BaseStream in a hand-made thread to bypass the automatic output conversion to Unicode.

The example above is for launching Gnuplot which needs two environment variables setting. When setting environment variables you have to UseShellExecute = False.

If you want to know the exit code of the process, check the ExitCode property once the process has completed.

partial 'subprocess' implementation

By Jeff Hardy, available here.

By Daniel Dotsenko, (Jeff's code circa 2009, changed to support binary output capture, redirecting to file-like or file descriptors, implemented communicate()) available here.

subprocess/.NET comparison

This comparison may help people not familiar with .NET API.

subprocess:

def run_command(args, input=None):
    """run_command(args, input=None) -> stdoutstring, stderrstring, returncode
    Runs the command, giving the input if any.
    The command is specified as a list: 'ls -l' would be sent as ['ls', '-l'].
    Returns the standard output and error as strings, and the return code"""
    from subprocess import Popen, PIPE
    p = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE)
    stdout, stderr = p.communicate(input)
    return stdout, stderr, p.returncode

.NET:

def run_command(args, input=None):
    from System.Diagnostics import Process
    p = Process()
    have_stdin = input is not None
    p.StartInfo.UseShellExecute = False
    p.StartInfo.RedirectStandardInput = have_stdin
    p.StartInfo.RedirectStandardOutput = True
    p.StartInfo.RedirectStandardError = True
    p.StartInfo.FileName = args[0]

    # not a precise way to join these! See list2cmdline in CPython's subprocess.py for the proper way.
    p.StartInfo.Arguments = " ".join(args[1:])

    p.Start()
    if have_stdinA:
        p.StandardInput.Write(input)
    p.WaitForExit() 
    stdout = p.StandardOutput.ReadToEnd()
    stderr = p.StandardError.ReadToEnd()
    return stdout, stderr, p.ExitCode

Back to Contents.

TOOLBOX
LANGUAGES