Repository: IronLanguages/ironpython3

Issue #961: Changes to the Shared IO are not picked up
Created: 2020-10-06T16:18:09Z
The following program does not write to memoryStream as expected (regression from IronPython 2):
var memoryStream = new MemoryStream();
var engine = Python.CreateEngine();
engine.Runtime.IO.SetOutput(memoryStream, System.Text.Encoding.Default);
engine.Execute("print('Hello world')");
It appears that the SharedIO streams are read when the PythonContext is created (which occurs on Python.CreateEngine). Because of this any changes after the fact are not picked up. In IronPython 2 there is a check for changes in PythonFile.GetWriter. A simple solution might be to use SharedIO.GetStreamProxy in PythonIOModule.CreateConsole instead of using the streams directly.
Workaround is to call SetOutput before creating of the engine:
var runtime = Python.CreateRuntime();
runtime.IO.SetOutput(memoryStream, System.Text.Encoding.Default);
var engine = Python.GetEngine(runtime);
Note: we should probably have a test for the redirected IO.

Duplicate issue #1311: SetOutput to stream doesn't work (3.4.0-alpha1)
Created: 2022-01-24T06:11:03Z
Description
We're attempting to capture the output to a stream. It is never called.
*Note: This used to work in the Iron Python 2 version - we're using the same codebase.
Steps to Reproduce
This example will demonstrate how the stdout isn't being captured by the stream assignment. The iron python script is running in a thread in a loop printing to the stdout. The assignment to the SetOutput stream is set but the stream is never written to.
     public class StreamWriteEvent : MemoryStream {

      public event EventHandler<string> OnNewText;

      public override void Write(byte[] buffer, int offset, int count) {

        OnNewText?.Invoke(this, Encoding.Default.GetString(buffer, offset, count));

        base.Write(buffer, offset, count);
      }

      public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) {

        OnNewText?.Invoke(this, Encoding.Default.GetString(buffer, offset, count));

        return base.WriteAsync(buffer, offset, count, cancellationToken);
      }

      public override void WriteByte(byte value) {

        OnNewText?.Invoke(this, value.ToString());

        base.WriteByte(value);
      }

      public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) {

        OnNewText?.Invoke(this, Encoding.Default.GetString(buffer, offset, count));

        return base.BeginWrite(buffer, offset, count, callback, state);
      }
    }

    ScriptEngine _engine;
    ScriptScope _scope;

    // Run a python script in a new thread
    private void button2_Click(object sender, EventArgs e) {

      Thread ts = new Thread(runScript);
      ts.Start();
    }

    // This thread is running the python script
    void runScript() {

      var streamWriter = new StreamWriteEvent();
      streamWriter.OnNewText += StreamWriter_OnNewText;

      _engine = IronPython.Hosting.Python.CreateEngine();

      _engine.Runtime.IO.SetErrorOutput(streamWriter, Encoding.ASCII);
      _engine.Runtime.IO.SetOutput(streamWriter, Encoding.ASCII);

      _scope = _engine.CreateScope();

      // Run a script that loops
      // We will test both capturing the output stream & the Shutdown command to stop the running script
      var sc = _engine.CreateScriptSourceFromString(@"
while True:
  print('This should output something')
");

      var ret = sc.Execute(_scope);

      // This doesn't do anything. It doesn't stop the running script.
      Console.WriteLine("Shut down");
    }

    private void StreamWriter_OnNewText(object sender, string e) {

      // This should output but never does
      Console.WriteLine("From steam writer" + e);
    }

    // This is the button that should stop the running python script
    private void button3_Click(object sender, EventArgs e) {

      Console.WriteLine("Shutting down...");

      // This shutdown command doesn't work. The script will continue running.
      _scope.Engine.Runtime.Shutdown();
    }
Expected behavior:
The stream contains the output of the print() statement
Actual behavior:
No output from print() statements in the stream
Versions
3.4.0-alpha1 for .Net Framework 4.7.2 from nuget

Closing comment (2022-01-24T14:45:07Z): This is probably the same as #961. A potential workaround is noted in that issue:
var runtime = IronPython.Hosting.Python.CreateRuntime();

runtime.IO.SetErrorOutput(streamWriter, Encoding.ASCII);
runtime.IO.SetOutput(streamWriter, Encoding.ASCII);

_engine = IronPython.Hosting.Python.GetEngine(runtime);