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=1328

  • Anonymous
    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?