2

I have a unity (C#) app that is calling a python script by initialising a child process.

When trying to write to the python std::in, I seem to be getting a

write fault on path

error when writing to STD::IN.

When reading from the process's STD::OUT, I get null as a value output.

What's the best way to pipe to the python process for input/output?

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using System.Diagnostics;

public class PythonCaller : MonoBehaviour
{
private string buffer = "";
private Process pythonML;

// Use this for initialization
void Start () {
    this.pythonML = new System.Diagnostics.Process();
    this.pythonML.StartInfo.FileName = "/bin/bash";
    this.pythonML.StartInfo.Arguments =
        "{{path to python executable}}/python {{path to python script}}/test.py";
    this.pythonML.StartInfo.UseShellExecute = false;
    this.pythonML.StartInfo.RedirectStandardInput = true;
    this.pythonML.StartInfo.RedirectStandardOutput = true;
    this.pythonML.StartInfo.RedirectStandardError = true;
    this.pythonML.Start();
    this.pythonML.BeginOutputReadLine();
    this.pythonML.OutputDataReceived += new DataReceivedEventHandler((sender, e) => {
        UnityEngine.Debug.Log(e.Data);
    });
    this.pythonML.WaitForExit();
}

// Update is called once per frame
void Update () {
    foreach (char c in Input.inputString) {
        if (c == '\b') {
            if (this.buffer.Length > 0) {
                this.buffer = this.buffer.Substring(0, this.buffer.Length - 1);
            }
        } else if (c == '\n' || c == '\r') {
            try {
                UnityEngine.Debug.Log(this.buffer);
                this.pythonML.StandardInput.WriteLine(this.buffer);

            }
            catch (IOException e) {
                UnityEngine.Debug.Log(e.Message);
            }

            this.buffer = "";
        } else {
            this.buffer += c;
        }
    }
}

}

PYTHON CODE:

print('hello world!')
Loveen Dyall
  • 824
  • 2
  • 8
  • 20
  • Add the Python code that reads from stdin as well please. – Woody1193 Oct 11 '18 at 20:01
  • Hi Thanks for your comment, I'm still getting the error InvalidOperationException: Standard input has not been redirected System.Diagnostics.Process.get_StandardInput () – Loveen Dyall Oct 11 '18 at 20:39
  • It looks like your Python code has a `return` statement that would allow the `while` loop to execute exactly once. So, you'd only be looking to accept input for a short amount of time so it's possible the Python code isn't receiving when the C# code sends – Woody1193 Oct 11 '18 at 20:49
  • It has been removed to little effect (it wasn't the cause in the first place as it was outside of the while loop). also looked at this https://stackoverflow.com/questions/2380649/redirect-python-standard-input-output-to-c-sharp-forms-application which hasn't helped – Loveen Dyall Oct 11 '18 at 20:51
  • This might seem like a silly question, but have you tried debugging through this code? If so, can you tell me what the value of `StartInfo.RedirectStandardInput` is after you get the `Process` is? – Woody1193 Oct 11 '18 at 20:55
  • Process process = Process.GetProcessById(processId); UnityEngine.Debug.Log(process.StartInfo.RedirectStandardInput); process.StartInfo.UseShellExecute = false ; process.StartInfo.RedirectStandardInput = true; process.StartInfo.RedirectStandardOutput = true; outputs false – Loveen Dyall Oct 11 '18 at 20:59
  • All that appears to be correct. The only problem remaining that I could think of would be trust issues. In order for two applications to communicate this way, they must have full trust. Can you verify that? – Woody1193 Oct 11 '18 at 21:00
  • According to [this](https://stackoverflow.com/questions/31171592/write-to-stdin-of-a-running-process-in-windows) it might not be possible if the process is already running. You could try using sockets though – Woody1193 Oct 11 '18 at 21:04
  • Okay I'll try using sockets. I was attempting to avoid using anything involving the network layer but that's fine – Loveen Dyall Oct 11 '18 at 21:07
  • If you don't mind having the C# program start the Python program then you could possibly get around it. Otherwise, it seems like it'd be a more difficult prospect – Woody1193 Oct 11 '18 at 21:08
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/181751/discussion-between-loveen-dyall-and-woody1193). – Loveen Dyall Oct 12 '18 at 10:23

2 Answers2

1

I think you need to redirect standard input for this to work. You already have that line, it's just commented out.

process.StartInfo.RedirectStandardInput = true;

Check this MSDN example for more info.

shapov
  • 46
  • 5
1

The way you're writing to StandardInput from the C# side is how I would expect it to work, given this and assuming that you already tried to run your method with process.StartInfo.RedirectStandardInput set to true. So, the only way I could see this not working is if your Python code (which you should attach to the question) wasn't reading stdin properly.

According to this, you can do that by either reading sys.stdin like a file, prompting the user for input or getting command-line arguments. Since you stated that your Python program is currently running, my guess is that you want to use either read or readlines to do that. Note that after you've done that you should uncomment process.StartInfo.RedirectStandardInput = true;.

Woody1193
  • 7,252
  • 5
  • 40
  • 90