Scripting C# with Iron Python

February 15, 2017

I wanted to integrate IronPython into one of my C# applications. The following code is a proof of concept for this.

This python script is defined in the file script.py

def process(pString, pAgreement):
  if float(pAgreement.balance) > 100.0:
    return pAgreement.agreementNumber
  else:
    return pAgreement.product

txt = process(txt, agreement)

Here's the C# code involved.

using IronPython.Hosting;
using Microsoft.Scripting;
using Microsoft.Scripting.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IronPythonTest
{

First we define a data structure which we'll pass through to the script. Note the virtual keyword here - without this the script won't be able to see the attributes on the object.

    public class Agreement
    {
        virtual public string agreementNumber { get; set; }
        virtual public string balance { get; set; }
        virtual public string product { get; set;  }
    }

Next we create a console application and run the execute method

    class Program
    {
        private ScriptEngine m_engine = Python.CreateEngine();
        private ScriptScope m_scope = null;

        static void Main(string[] args)
        {
            Program lProgram = new Program();
            lProgram.execute();
        }

This method creates a scope for the script execution, then creates a string which is passed to the script as variable txt.

        private void execute()
        {
            this.m_scope = this.m_engine.CreateScope();

            String lText = "Quick Brown Fox Lazy Dog";
            this.m_scope.SetVariable("txt", lText);

We then create a new Agreement instance, populate it, and pass that through to the script as agreement

            Agreement lAgreement = new Agreement();
            lAgreement.agreementNumber = "ABC123";
            lAgreement.balance = "123.45";
            lAgreement.product = "UPL";
            this.m_scope.SetVariable("agreement", lAgreement);

Now we read in the script.py file, and execute it. Note the SourceCodeKind.AutoDetect here - I initially had this set to SourceCodeKind.SingleStatement which caused all sorts of problems when I was passing a multiline script. The execution failed because it didn't expect the second line of code.

            string lCode = System.IO.File.ReadAllText("script.py");

            ScriptSource source = m_engine.CreateScriptSourceFromString(lCode, SourceCodeKind.AutoDetect);
            source.Execute(m_scope);

Finally, we get the value of the variables after our script has completed.

            var lUpdatedText = m_scope.GetVariable<string>("txt");
            var lUpdatedAgreement = m_scope.GetVariable<Agreement>("agreement");

            Console.WriteLine(lUpdatedText);
        }
    }
}

Tags: c# ironpython python