How to use IronPython

IronPython is an implementation of Python programming language for dotNET. The seamless integration of Python into the dotNET environment promises many advantages. The latest stable version is compatible with Python 2.7, but also is a preview available which is compatible with Python 3.4. In this post I will show how to use version 2.7.

Preparations

The first step is to download three NuGet packages:

  1. IronPython
  2. DynamicLanguageRuntime
  3. IronPython Standard Library

After adding the packages to the project it should looks like this:

image

Now it is necessary to import the namespaces

  • IronPython
  • Microsoft.Scripting.Hosting
  • System.Text

image

Now we can use IronPython in the Invoke Code Activity.

The following examples are based on a tutorial of the IronPython C# integration by Needful Software Ltd.

Execute Python Code

The first example shows how to execute Python code. The source can be a string or a file, in our case only to output a Hello World. We create a Python engine and set the standard output and standard error output to a memory stream. Now we create a script, execute it and catch the output.

//-Begin----------------------------------------------------------------

string pythonCode = @"
print 'Hello World!'
";

ScriptEngine pythonEngine = IronPython.Hosting.Python.CreateEngine();

MemoryStream stdout = new MemoryStream();
pythonEngine.Runtime.IO.SetOutput(stdout, Encoding.Default);
MemoryStream stderr = new MemoryStream();
pythonEngine.Runtime.IO.SetErrorOutput(stderr, Encoding.Default);

ScriptSource pythonScript;
//-Python script from an internal string literal------------------------
pythonScript = pythonEngine.CreateScriptSourceFromString(pythonCode);

//-Python script from an external file----------------------------------
//pythonScript = pythonEngine.CreateScriptSourceFromFile("HelloWorld.py");

try {

  pythonScript.Execute();

  string stdOut = Encoding.Default.GetString(stdout.ToArray());
  string stdErr = Encoding.Default.GetString(stderr.ToArray());

  if(!String.IsNullOrEmpty(stdOut)) {
    Console.WriteLine(stdOut);
  } else {
    Console.WriteLine(stdErr);
  }

} catch (Exception ex) {
  Console.WriteLine(ex.Message);
}

//-End------------------------------------------------------------------

With this, we have already learned the most important basics.

image

Use of Additional Python Libraries

The example below shows how to use Python base64 library. Here we add the path to the library collection of Python, which we have installed with IronPython standard library. The rest of the code remains unchanged.

//-Begin----------------------------------------------------------------

ScriptEngine pythonEngine = IronPython.Hosting.Python.CreateEngine();

MemoryStream stdout = new MemoryStream();
pythonEngine.Runtime.IO.SetOutput(stdout, Encoding.Default);
MemoryStream stderr = new MemoryStream();
pythonEngine.Runtime.IO.SetErrorOutput(stderr, Encoding.Default);

ICollection<string> searchPaths = pythonEngine.GetSearchPaths();
string UserPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
searchPaths.Add(UserPath + "\\.nuget\\packages\\ironpython.stdlib\\2.7.11\\content\\Lib");
pythonEngine.SetSearchPaths(searchPaths);

ScriptSource pythonScript = pythonEngine.CreateScriptSourceFromFile("HelloWorldBase64.py");

try {

  pythonScript.Execute();

  string stdOut = Encoding.Default.GetString(stdout.ToArray());
  string stdErr = Encoding.Default.GetString(stderr.ToArray());

  if(!String.IsNullOrEmpty(stdOut)) {
    Console.WriteLine(stdOut);
  } else {
    Console.WriteLine(stdErr);
  }

} catch (Exception ex) {
  Console.WriteLine(ex.Message);
}

//-End------------------------------------------------------------------

Here the Python code:

#-Begin-----------------------------------------------------------------

import base64

originalString = "Hello World!"
print "Original string: " + originalString

encodedString = base64.b64encode(originalString)
print "Encoded string: " + encodedString

decodedString = base64.b64decode(encodedString)
print "Decoded string: " + decodedString

#-End-------------------------------------------------------------------

image

Set and Get Variables

Here now an example to exchange variables between the Python code and the UiPath workflow.

//-Begin----------------------------------------------------------------

string pythonCode = @"
helloWorldString = 'Hello World!'
print helloWorldString
print externalString
";

ScriptEngine pythonEngine = IronPython.Hosting.Python.CreateEngine();

MemoryStream stdout = new MemoryStream();
pythonEngine.Runtime.IO.SetOutput(stdout, Encoding.Default);
MemoryStream stderr = new MemoryStream();
pythonEngine.Runtime.IO.SetErrorOutput(stderr, Encoding.Default);

ScriptScope scope = pythonEngine.CreateScope();
//-Set a Python variable------------------------------------------------
scope.SetVariable("externalString", "How do you do?");

ScriptSource pythonScript = pythonEngine.CreateScriptSourceFromString(pythonCode);

try {

  pythonScript.Execute(scope);

  string stdOut = Encoding.Default.GetString(stdout.ToArray());
  string stdErr = Encoding.Default.GetString(stderr.ToArray());

  if(!String.IsNullOrEmpty(stdOut)) {
    Console.WriteLine(stdOut);

    //-Get a Python variable--------------------------------------------
    Console.WriteLine("helloWorldString: " + scope.GetVariable("helloWorldString"));
    Console.WriteLine("externalString: " + scope.GetVariable("externalString"));

  } else {
    Console.WriteLine(stdErr);
  }

} catch (Exception ex) {
  Console.WriteLine(ex.Message);
}

//-End------------------------------------------------------------------

As we can see, this is very comfortable possible via the SetVariable and GetVariable methods in the context of a scope.

Show Yourself

The following Python code …

string pythonCode = @"
import sys
print(""Python version:"")
print (sys.version)
print(""Version info:"")
print (sys.version_info)
";

… delivers this.

image

Conclusion

IronPython offers us another interesting integration scenario. The nearness of this Python implementation to dotNET opens up easy possibilities for us to use it seamlessly with UiPath. Sure, the stable 2.7 release is already a bit “grayed out”, but a 3.4 release is being worked on. And the perspective that the 3.4 release will also be available for dotNET 5 makes things even more interesting. Overall, an interesting alternative.

Addendum 11.09.2022: The approach presented here is deprecated, because it the IronPython.StdLib package is not available for x64, so it can’t work in the Windows compatibility mode.

4 Likes