Knowledge is power. We love to share it.

News related to Mono products, services and latest developments in our community.

mzilic

Hosting IronPython in WinForms

10/02/2011

Introduction

IronPython is an open source implementation of the Python programming language for .NET Framework. Python itself is an interpreted high-level programming language; it is often compared to Java or Ruby. Python has a very clear and readable syntax, intuitive object oriented approach and it is embeddable within applications via scripting interface. If you are new to Python I recommend browsing through the python documentation.

IronPython is implemented on top of the Dynamic Language Runtime (DLR). DLR makes it easier to develop dynamic languages which are intended to run on .NET Framework. DLR is essentially a library which runs on top of the Common Language Runtime.

Python is often embedded in applications to allow a plug-in like functionality; because Python is also a high-level, dynamic and interpreted programming language it is also easy to add new functionality. IronPython might be useful in scenarios where your customers require custom business logic. Your application could perform main operations on the data while the scripts would contain the business logic and could easily be edited on-site and quickly deployed to your customers. It is also worth mentioning that some standard Python libraries might not work with IronPython.

The goal of this article is to show you:
• how to include IronPython in your Application
• how to work with the basic Python data structures and a simple for loop
• how to execute Python scripts and retrieve values from methods
• how to call Python methods using the dynamic keyword

Creating a project

First you will need to download and install IronPython, which you can do here. After you've installed IronPython it is time to create a new WinForms project.
projectscreen

Next, you need to reference IronPython assemblies. Please note that IronPython will not be registered in Add References dialog box so you will have to manually navigate to the IronPython installation directory and add references from there.

You can always add the assemblies manually to the Add References dialog box, you can learn more in this article. Please note that this only works for Visual Studio 2008. For Visual Studio 2010 you need to add a new key at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\.NETMinimumVersion\AssemblyFoldersEx
addreference

Your first script

First you need to add a new python file to your project. Right click on the project and select Add -> New Item. Select a text file and name it script.py.
pythonfile

After you've added the file you will need to right click on the script.py in Solution Explorer, select Properties and set Copy to Output Directory to Copy always
copyalways

Now it's time to open the script.py and write our python code. Please note that indention is very important in Python programming.
def HelloWorld():
    return 'Hello World'
     
def SimpleLoop():
    retVal = 0
    for i in range(1, 10):
        retVal = retVal + i
    return retVal
         
def List():
    return [1, 2, 3]
         
def Dictionary():
    return {"1" : "1", "2" : "2"}

In the code I am demonstrating a for loop, lists and dictionaries. In Python, a list is always declared with angle ("[]") brackets and commas are used to separate the values. Dictionary is always declared with curly ("{}") brackets and keys and values are also separated with commas. Python lists can contain any type: integers, floats, string or other lists. Same also applies to dictionaries.

Executing the script

In this part I will show you how to get a list of methods in the script, how to call these methods and how to get the results.

Now it's time to come back to the Windows Forms project. I added a combobox, a textbox and a button onto the form. I used the combobox to list out available methods, textbox shows the python output and the button calls the selected python function.
winform

This is the code which I used to extract the method names from the script.
private void ExtractMethods()
        {
            try
            {
                ScriptEngine engine = Python.CreateEngine();
                // not exactly by the book     
                ScriptScope scope = engine.ExecuteFile("script.py");
                foreach (var item in scope.GetItems().Where(p => p.Value is IronPython.Runtime.PythonFunction))
                {
                    comboBox1.Items.Add(item.Key);
                }
                engine.Runtime.Shutdown();
            }
            catch{}
        }
I actually executed the whole script to see the contents; this is not something you'll be doing in an actual business environment scenario. However, there will be times when you will need to see a list of methods in a particular script and this is one example of how to do it.

This is the code which I used to call the methods and grab the return values.
private void CallPythonMethod(string methodName)
        {
            try
            {
                ScriptEngine engine = Python.CreateEngine();
                ScriptScope scope = engine.ExecuteFile("script.py");
                var v = engine.Operations.Invoke(scope.GetVariable(methodName));
                textBox1.Text = "Result: ";
                if (v is string)
                    textBox1.Text += v;
                else if (v is int)
                    textBox1.Text += ((int)v).ToString();
                else if (v is IronPython.Runtime.List)
                    ((IronPython.Runtime.List)v).ToList().ForEach(p => textBox1.Text += string.Format("{0}{1}", Environment.NewLine, p.ToString()));
                else if (v is IronPython.Runtime.PythonDictionary)
                {
                    foreach (var item in ((IronPython.Runtime.PythonDictionary)v))
                    {
                        textBox1.Text += string.Format("{2}key: {0}, value {1}", item.Key, item.Value, Environment.NewLine);
                    }
                }
                engine.Runtime.Shutdown();
            }
            catch
            {
                textBox1.Text = string.Format("Error executing: {0}", methodName);
            }
        }
As you can see, our script is executed every time this method is called. In a realistic scenario you will probably find this redundant. However, it is useful in scenarios where Python source code changes and you want to see these change take effect without restarting the application.

Using the dynamic keyword

Dynamic keyword is a new feature in C# 4.0. DLR was originally part of the first framework of IronPython, and has since been used to introduce new features into C# 4.0. One of them is the dynamic keyword.

In this final part I want to show you how to call Python methods using the dynamic keyword:
ScriptRuntime runtime = Python.CreateRuntime();
dynamic script = runtime.UseFile("script.py");
script.HelloWorld();

Please note that because IronPython is an interpreted scripting language it relies on the dynamic keyword which in turn breaks strong type checking.

Conclusion

This article is meant to introduce you to IronPython and to show you the very basics of hosting IronPython in your Application and how to call scripts from your Application. I will demonstrate more advanced features in a follow up article in the near future. You can download the source code used in this article below.
Rated 5.00, 2 vote(s).