How to redirect output from python using the DLR Hosting API
This
is the 3rd in the series of 'How To' posts on using the DLR Hosting API to host
languages like IronPython,
IronRuby, Toyscript
etc in a managed application. The first 2 posts are here
and here.
The
DLR Hosting API provides the ScriptIO class to give
you complete control over the input, output and error streams used by the
scripting languages. The Hosting API describes ScriptIO like this - “This class let's you control input and output by default
for dynamic code running via DLR hosting. You can access the instance of this class from the IO property on
ScriptRuntime
.”
Here's
the step by step guide to redirect the output to a Stream object using the
ScriptIO class.
1) Create the runtime,
the python engine and a MemoryStream object
ScriptRuntime runTime = ScriptRuntime.Create();
ScriptEngine
pyEngine = runTime.GetEngine("py");
MemoryStream ms = new MemoryStream();
2) Set the memory
stream created above as the output stream for this script runtime.( The API can
redirect output to any Stream
object. So you can also use a FileStream
object to capture output).
runTime.IO.SetOutput(ms,
new StreamWriter(ms));
3) Execute a python
code snippet that would output something.
ScriptSource ss =
pyEngine.CreateScriptSourceFromString(
"print 'hello world'",
SourceCodeKind.Statements);
ss.Execute();
4) Read from the
memory stream object created in step (2).
string str =
ReadFromStream(ms);
5) ‘str’ will now
contain the output from the script.
The input and error streams can also be set using the above technique and calling the appropriate method in ScriptIO.
Refer to the
DLR Hosting API spec to learn more about the ScriptIO and other
related classes.
The full sample follows.
Normally you wouldn’t care to redirect the output, input or error streams in a
console application. In spite of this, I am sticking to a console application as
it lets me demonstrate the API usage succinctly and provide a full copy &
paste enabled sample
using System;
using System.IO;
using
System.Scripting;
using
System.Text;
using
Microsoft.Scripting.Hosting;
namespace
ConsoleApplication1 {
class Program {
public static void Main(string[] args) {
ScriptRuntime
runTime = ScriptRuntime.Create();
ScriptEngine
pyEngine = runTime.GetEngine("py");
MemoryStream ms = new MemoryStream();
//runTime.IO
refers to the current runtime's IO property
runTime.IO.SetOutput(ms, new StreamWriter(ms));
ScriptSource
ss =
pyEngine.CreateScriptSourceFromString(
"print 'hello
world'",
SourceCodeKind.Statements);
ss.Execute();
string
str = ReadFromStream(ms);
ms.Close();
Console.WriteLine(str);
}
private
static string
ReadFromStream(MemoryStream ms) {
int
length = (int)ms.Length;
Byte[]
bytes = new Byte[length];
ms.Seek(0, SeekOrigin.Begin);
ms.Read(bytes, 0, (int)ms.Length);
return
Encoding.GetEncoding("utf-8").GetString(bytes, 0, (int)ms.Length);
}
}
}
Comments
Anonymous
July 08, 2008
PingBack from http://stocks-options-trading.info/options-trading/?p=1328Anonymous
March 02, 2010
Why does SetOutput() need both a string and a textwriter? I would think that one or the other would be used. When is the stream used as opposed to the writer?Anonymous
June 22, 2011
Hi! I'm writing some code with DLR, C# and Ironpython on VS2010. My script from ironpython prints to screen, I want to catch that with C#. I'm doing exactly what you've posted, but it is not working. The MemoryStream object is always empty. Any clue?