How can I call (Iron)Python code from a C# app?

56,550

Solution 1

The process is simple, especially in a C#/.NET 4 application where support for dynamic languages have been improved via usage of the dynamic type. But it all ultimately depends on how you intend to use the (Iron)Python code within your application. You could always run ipy.exe as a separate process and pass your source files in so they may be executed. But you probably wanted to host them in your C# application. That leaves you with many options.

  1. Add a reference to the IronPython.dll and Microsoft.Scripting.dll assemblies. You'll usually find them both in your root IronPython installation directory.

  2. Add using IronPython.Hosting; to the top of your source and create an instance of the IronPython scripting engine using Python.CreateEngine().

  3. You have a couple of options from here but basically you'd create a ScriptScope or ScriptSource and store it as a dynamic variable. This allows you to execute it or manipulate the scopes from C# if you choose to do so.

Option 1:

Using CreateScope() to create an empty ScriptScope to use directly in C# code but usable in Python sources. You can think of these as your global variables within an instance of the interpreter.

dynamic scope = engine.CreateScope();
scope.Add = new Func<int, int, int>((x, y) => x + y);
Console.WriteLine(scope.Add(2, 3)); // prints 5

Option 2:

Using Execute() to execute any IronPython code in a string. You can use the overload where you may pass in a ScriptScope to store or use variables defined in the code.

var theScript = @"def PrintMessage():
    print 'This is a message!'

PrintMessage()
";

// execute the script
engine.Execute(theScript);

// execute and store variables in scope
engine.Execute(@"print Add(2, 3)", scope);
// uses the `Add()` function as defined earlier in the scope

Option 3:

Using ExecuteFile() to execute an IronPython source file. You can use the overload where you may pass in a ScriptScope to store or use variables defined in the code.

// execute the script
engine.ExecuteFile(@"C:\path\to\script.py");

// execute and store variables in scope
engine.ExecuteFile(@"C:\path\to\script.py", scope);
// variables and functions defined in the scrip are added to the scope
scope.SomeFunction();

Option 4:

Using GetBuiltinModule() or the ImportModule() extension method to create a scope containing the variables defined in said module. Modules imported this way must be set in the search paths.

dynamic builtin = engine.GetBuiltinModule();
// you can store variables if you want
dynamic list = builtin.list;
dynamic itertools = engine.ImportModule("itertools");
var numbers = new[] { 1, 1, 2, 3, 6, 2, 2 };
Console.WriteLine(builtin.str(list(itertools.chain(numbers, "foobar"))));
// prints `[1, 1, 2, 3, 6, 2, 2, 'f', 'o', 'o', 'b', 'a', 'r']`

// to add to the search paths
var searchPaths = engine.GetSearchPaths();
searchPaths.Add(@"C:\path\to\modules");
engine.SetSearchPaths(searchPaths);

// import the module
dynamic myModule = engine.ImportModule("mymodule");

You can do quite a lot hosting Python code in your .NET projects. C# helps bridging that gap easier to deal with. Combining all the options mentioned here, you can do just about anything you want. There's of course more you can do with the classes found in the IronPython.Hosting namespace, but this should be more than enough to get you started.

Solution 2

To run a function you can't call it like in Option 3 of Jeff Mercado's response (which is a great and very helpful one! But this option doesn't compile, at least on .NET 4.5). You can use ScriptScope.GetVariable to get the actual function and then you can call it like a C# function. Use it like this:

C# code:

var var1,var2=...
ScriptEngine engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
engine.ExecuteFile(@"C:\test.py", scope);
dynamic testFunction = scope.GetVariable("test_func");
var result = testFunction(var1,var2);

Python code:

def test_func(var1,var2):
    ...do something...

Took me a while to finally figure it out, and it's quite simple.. Too bad there's no good IronPython documentation. Hope this helps :)

Solution 3

1) Need to install

Install-Package DynamicLanguageRuntime -Version 1.2.2

2) Need to add "Iropython.dll" using this: https://www.webucator.com/how-to/how-add-references-your-visual-studio-project.cfm

3) Need to Use

using IronPython.Hosting;
using IronPython.Runtime;
using IronPython;
using Microsoft.Scripting.Hosting;
using Microsoft.Scripting;

3) Need to set var

ScriptEngine engine = Python.CreateEngine();
Share:
56,550
David Thielen
Author by

David Thielen

I have a wonderful wife, 3 terrific daughters, and 2 great dogs. In my spare time I read history and blog on political topics, including interviewing many of the elected officials here in Colorado (from both parties). I was CEO &amp; founder at Windward Studios (sold it in 2021) I've written operating systems (including on the Win95 team at Microsoft), games (including Enemy Nations), applications, firmware, and enterprise server systems. For the last 10 years I've been in both the Java and .NET world, mostly server side for Java, and both apps (Office AddIns) and server for C#. And for the last 3 years JavaScript/TypeScript also. (And truth to be told, since becoming CEO 2+ years ago I don't get to program much.) I've written a couple of books (including No Bugs! (free copy)) and numerous magazine articles. My email is [email protected] if you need to contact me.

Updated on January 31, 2020

Comments

  • David Thielen
    David Thielen over 4 years

    Is there a way to call Python code, using IronPython I assume, from C#? If so, how?