ironpython3
ironpython3 copied to clipboard
SetOutput to stream doesn't work (3.4.0-alpha1)
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
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);
Thank you - that works. It's a strange workaround but it works :D
Thank you - that works. NB
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 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.