Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redirect Python standard input/output to C# forms application

I apologize if this is a duplicate question, I searched a bit and couldn't find anything similar - I have a Python library that connects to my C# application via a socket in order to allow simple Python scripting (IronPython isn't an option right now for a couple of reasons). I would like to create a Windows Forms control that would be basically a graphical front-end for the Python interpreter, so that the user could run the interpreter without having to have a separate console window open.

I attached a simple demo of what I've tried so far below, but I haven't been able to get it to work. The DataReceived event handlers are never called, and when I try to write to the standard input nothing happens in the interpreter. Does anyone have any feedback about what I'm doing wrong, or if this is even possible?

public partial class Form1 : Form
{

    Process _pythonProc;

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        ProcessStartInfo psi = new ProcessStartInfo()
        {
            FileName = @"C:\Python26\Python.exe",
            CreateNoWindow = true,
            UseShellExecute = false,
            RedirectStandardInput = true,
            RedirectStandardOutput = true,
            RedirectStandardError = true
        };
        _pythonProc = new Process();
        _pythonProc.OutputDataReceived += OutputDataReceived;
        _pythonProc.ErrorDataReceived += ErrorDataReceived;
        _pythonProc.StartInfo = psi;
        _pythonProc.Start();
    }

    private void cmdExecute_Click(object sender, EventArgs e)
    {
        string cmd = textInput.Text;
        _pythonProc.StandardInput.WriteLine(cmd);
        _pythonProc.StandardInput.Flush();
        textInput.Text = string.Empty;
    }

    private void Form1_FormClosed(object sender, FormClosedEventArgs e)
    {
        if (!_pythonProc.HasExited)
            _pythonProc.Kill();
    }

    private void OutputDataReceived(object sender, DataReceivedEventArgs args)
    {
        textOutput.Text += args.Data;
    }

    private void ErrorDataReceived(object sender, DataReceivedEventArgs args)
    {
        textOutput.Text += args.Data;
    }

}
like image 756
Chris Vig Avatar asked Dec 02 '22 06:12

Chris Vig


2 Answers

In case anyone else stumbles across this, I figured out the problem - by default, the Python interpreter only enters interactive mode if it detects that a TTY device is connected to standard input (which is normally only true if the program is run from the console). In order to redirect the standard IO streams, you have to set UseShellExecute in the ProcessStartInfo to false, which causes the interpreter to think that there is no TTY connected, meaning it immediately exits since it has nothing to do.

The solution is to run the Python interpreter with the "-i" command line argument, which forces the interpreter to interactive mode, regardless of whether there is a TTY connected to standard in. This makes the example above work correctly.

like image 186
Chris Vig Avatar answered Dec 18 '22 10:12

Chris Vig


write in separate thread:

while(cond)
{
   string s = _pythonProc.StandardOutput.ReadLine();
   textOutput.Invoke( () => { textOutput.Text += s; } );
}
like image 36
Andrey Avatar answered Dec 18 '22 12:12

Andrey