ironpython3 icon indicating copy to clipboard operation
ironpython3 copied to clipboard

SetOutput to stream doesn't work (3.4.0-alpha1)

Open DJSures opened this issue 3 years ago • 5 comments

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

DJSures avatar Jan 24 '22 06:01 DJSures

This is probably the same as https://github.com/IronLanguages/ironpython3/issues/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);

slozier avatar Jan 24 '22 14:01 slozier

Thank you - that works. It's a strange workaround but it works :D

DJSures avatar Jan 26 '22 05:01 DJSures

Thank you - that works. NB

zhanglongtumi avatar Nov 05 '22 12:11 zhanglongtumi

Hi, I am using IronPython 3.4.0 and having a same problem. I am trying to redirect outputs to std IO. The default behavior does not work. So, I tried to redirect it explicitly, but it still doesn't work. Then I found this github issue and wanted to try the workaround. But there is not an overload of SetOutput() that taking TextWriter as its first parameter. Is it removed?

KanaHayama avatar Jan 19 '23 00:01 KanaHayama

@KanaHayama There is no overload with TextWriter as the first parameter, the streamWriter in the workaround is a Stream. If you need to use a TextWriter you can try wrapping it as described in the documentation on redirecting output.

slozier avatar Jan 21 '23 02:01 slozier