Hosting IronPython 1.1

 

A recurring topic on the IronPython mailing list is the subject of hosting IPy in another application.  Part of the reason the topic comes up frequently is that we keep changing the design (we're almost done doing that...we hope).

I thought it might be helpful to discuss where our hosting design has been, where it is, and where it's going within in the context of one consistent example.  To that end this is the first in a series of three posts that will focus on one host showing the following basic concepts:

  • Executing multiple statements of IronPython code in a single scope
  • Exposing host data to IronPython, and vice versa
  • Calling a host method in IronPython, and vice versa
  • Using delegates

I'll start by discussing IronPython 1.1 in this entry, current 2.0 Alphas in the next, and finish with the model coming in future 2.0 Alphas (likely >7).

 

IronPython 1.1 is the latest production version.  Released back in April 2007, this is the last version of IronPython not to be based on the Dynamic Language Runtime.  Meaning, this hosting model was designed primarily to support the hosting of IronPython only, and there is no Microsoft.Scripting.dll.

Here's our example host in C#:

using System;
using IronPython.Hosting; //From IronPython.dll

namespace Hosting1 {
    class Host {
        public static void Main() {
            //Create a PythonEngine to execute code
            //and an EngineModule to execute in.
            PythonEngine pe = new PythonEngine();
            EngineModule mod = pe.CreateModule("mymod", true);


            //Expose host data to IronPython and vice versa
            mod.Globals["mystring"] = "This is a C# string";
            pe.Execute("print mystring", mod);

            pe.Execute("mystring = 'This is a Python string'", mod);
            Console.WriteLine(mod.Globals["mystring"]);


            //Expose a host method to IronPython and vice versa
            HostAPI myapi = new HostAPI();
            mod.Globals["api"] = myapi;
            pe.Execute("api.Method()", mod);

            pe.Execute(@"def func():
    print 'This is a Python function'
", mod);
            pe.Evaluate("func()", mod);


            //Use delegates over the same two methods
            HostAPI.Del hostdel = new HostAPI.Del(myapi.Method);
            mod.Globals["hdel"] = hostdel;
            pe.Execute("hdel()", mod);

            HostAPI.Del ipydel = pe.CreateMethod<HostAPI.Del>("func()",
mod); ipydel(); } } public class HostAPI { public delegate void Del(); public void Method() { Console.WriteLine("This is a host method"); } } }

 

PythonEngine and EngineModule

Now let's dig a little deeper.  We've used only two types from the hosting APIs: PythonEngine, and EngineModule.

            PythonEngine pe = new PythonEngine();
            EngineModule mod = pe.CreateModule("mymod", true);

The PythonEngine is the primary entry point for code execution.  The EngineModule is a scope in which code gets executed.  PythonEngine exposes a DefaultModule, which you can use instead of creating your own EngineModule.  You will notice that PythonEngine.Execute and PythonEngine.Evaluate methods have overloads that do not take an EngineModule.  These overloads work against the DefaultModule.

EngineModule exposes a dictionary of defined names via its Globals property, which both host and scripts have read/write access to.  The host is free to insert any .NET type into the dictionary, which then exposes that type to IronPython script code.

            mod.Globals["api"] = myapi;

 

Delegates

The last major concept here is the usage of delegates.  .NET delegates are directly callable from IronPython.  No special magic is required on either the host or script's part.

            HostAPI.Del hostdel = new HostAPI.Del(myapi.Method);
            mod.Globals["hdel"] = hostdel;
            pe.Execute("hdel()", mod);

In the reverse, you can get a delegate to IronPython code in 1.1 via the PythonEngine.CreateMethod APIs.  Sometimes this is more convenient than calling PythonEngine.Evaluate or PythonEngine.Execute.

            HostAPI.Del ipydel = pe.CreateMethod<HostAPI.Del>("func()",
mod); ipydel();

 

Next...

In my next entry I'll take this same example, re-write it for IronPython 2.0 Alpha 6, and discuss how and why things changed.

In the meantime, if you'd like to read more about hosting IronPython, the Cookbook has some good examples.  And if there are any hosting concepts I haven't touched on that you wish I would, please let me know.

Published 28 November 07 08:29 by rdawson
Filed under: ,

Comments

# Free People Searches » Hosting IronPython 1.1 said on November 28, 2007 3:46 PM:

PingBack from http://www.absolutely-people-search.info/?p=737

# srivatsn said on November 29, 2007 2:58 AM:

Hi Ryan,

Good post! Waiting to get my hands on this.

# Ryan Dawson's Web Log said on November 29, 2007 4:59 PM:

We previously discussed the hosting model of IronPython 1.1 .&#160; This time around we'll see how that

# Noticias externas said on November 29, 2007 5:46 PM:

We previously discussed the hosting model of IronPython 1.1 .&#160; This time around we&#39;ll see how

Anonymous comments are disabled

About rdawson

Born and raised in Kansas City, Missouri. Graduated from the University of Missouri at Rolla. Moved to Redmond, Washington in 1999 where I've been working as a Software Development Engineer in Test for Microsoft ever since. In my spare time I enjoy riding my motorcycle and am learning to play the violin and speak French.

Search

Go

This Blog

Syndication

Page view tracker