Needful Software

IronPython C# Integration

2. Modules

Search paths

More often than not a Python script will depend on some module either a custom module or one from the Python Standard Library. We will show how to use the standard library but given the large number of modules in it we will start with a more basic example.

The only real difficulty in working with modules is setting up the list of paths where the engine will look for the modules. The ScriptEngine class provides a function to retrieve the current list of search paths: GetSearchPaths, and another to set the list: SetSearchPaths. SetSearchPaths replaces the existing list so if you want to add a search path you will need to get the current list first, add the new path to it, then pass that updated list to the SetSearchPaths function.

Let's illustrate calling a module with a simple example. We modify the example of the previous page so that HelloWorld.py imports another module called HelloWorldModule.py. We put both these files in the same directory as Program.cs. The source for both files is shown below.

The full example is available from our GitHub repository: IronPythonTutorials/CSharpIntegration/PythonScriptExecution3

 File: HelloWorldModule.py
def PrintHelloWorld():
    print 'Hello World!'
 File: HelloWorld.py
import HelloWorldModule

HelloWorldModule.PrintHelloWorld()

The Program.cs file is shown below. We have updated it to print out the initial list of search paths as returned by the GetSearchPaths function. Because when we launch the program from Visual Studio it will be executed from bin\\Debug we need to add ..\\.. to the list of searchs paths. We use the SetSearchPaths as shown to do so.We then execute the script as before.

 File: Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PythonScriptExecution3
{
    class Program
    {
        static void Main(string[] args)
        {
            Microsoft.Scripting.Hosting.ScriptEngine pythonEngine = 
                IronPython.Hosting.Python.CreateEngine();

            // Print the default search paths
            System.Console.Out.WriteLine("Search paths:");
            ICollection<string> searchPaths = pythonEngine.GetSearchPaths();
            foreach (string path in searchPaths)
            {
                System.Console.Out.WriteLine(path);
            }
            System.Console.Out.WriteLine();

            // Now modify the search paths to include the directory from
            // which we execute the script
            searchPaths.Add("..\\..");
            pythonEngine.SetSearchPaths(searchPaths);

            // Execute the script
            // We execute this script from Visual Studio
            // so the program will executed from bin\Debug or bin\Release
            Microsoft.Scripting.Hosting.ScriptSource pythonScript = 
                pythonEngine.CreateScriptSourceFromFile("..\\..\\HelloWorld.py");
            pythonScript.Execute();
        }
    }
}

Obviously this is a slightly contrived example as you would typically put the scripts in a more sensible location but you should get the idea.

If all went fine you should get the following output.

 Console output
Search paths:
.
C:\p4client2\Tutorials\Development\IronPython\Examples\CSharpIntegration\PythonS
criptExecution3\PythonScriptExecution3\bin\Debug\Lib
C:\p4client2\Tutorials\Development\IronPython\Examples\CSharpIntegration\PythonS
criptExecution3\PythonScriptExecution3\bin\Debug\DLLs

Hello World!
Press any key to continue . . .

But if for some reason a module can't be found you would get the following exception thrown.

 Exception thrown if a module can't be found
Unhandled Exception: IronPython.Runtime.Exceptions.ImportException: No module na
med os
   at Microsoft.Scripting.Runtime.LightExceptions.CheckAndThrow(Object value)
   at Microsoft.Scripting.Interpreter.FuncCallInstruction`2.Run(InterpretedFrame
 frame)
   at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame)
   at Microsoft.Scripting.Interpreter.LightLambda.Run1[T0,TRet](T0 arg0)
   at IronPython.Compiler.RuntimeScriptCode.InvokeTarget(Scope scope)
   at IronPython.Compiler.RuntimeScriptCode.Run()
   at Microsoft.Scripting.Hosting.ScriptSource.Execute()
   at PythonScriptExecution3.Program.Main(String[] args) in c:\p4client2\Tutoria
ls\Development\IronPython\Examples\CSharpIntegration\PythonScriptExecution3\Pyth
onScriptExecution3\Program.cs:line 16
Press any key to continue . . .

Let's have a closer look at the initial list of search paths.

By default the current working directory will be included in the list of search paths. However if you rely on this your application will work or not depending on what the current working directory is when the user launches the application. IronPython by default will also include in the search path two paths that are relative to where the application itself is installed: the Lib and DLLs paths you can see in the output above. These locations are a good choice to keep the modules together with the main application.

The IronPython implementation uses the Assembly.GetEntryAssembly() function to get the path of the host in order to add the "Lib" and "DLLs" paths. There are circumstances in which Assembly.GetEntryAssembly() will return null and these paths will then not be added. One such case is when the environment is ASP.NET.

The Standard Library

Using the standard library in your application is not difficult. A separate NuGet package is available that contains the standard library. This package will add all the standard library modules to the Visual Studio project. The issue that arises though is that the modules used by the application need to be distributed with it. How to to best do that depends on the particular circumstances. In the simplest case you can just put the required modules in the same directory as the application binary and distribute them together. If you opt for that solution the default search path should be sufficient as it includes the '.' directory.

Let's now show a simple example of a script using the standard library. The full example is available from our GitHub repository: IronPythonTutorials/CSharpIntegration/PythonScriptExecution4

Get the IronPython Standard Library with NuGet
Figure 1: Get the IronPython Standard Library with NuGet
Get the IronPython Standard Library with NuGet
Figure 2: Get the IronPython Standard Library with NuGet
 File: HelloWorldBase64.py
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
 File: Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PythonScriptExecution4
{
    class Program
    {
        static void Main(string[] args)
        {
            Microsoft.Scripting.Hosting.ScriptEngine pythonEngine = 
                IronPython.Hosting.Python.CreateEngine();

            // Print the default search paths
            System.Console.Out.WriteLine("Search paths:");
            ICollection<string> searchPaths = pythonEngine.GetSearchPaths();
            foreach (string path in searchPaths)
            {
                System.Console.Out.WriteLine(path);
            }
            System.Console.Out.WriteLine();

            // Now modify the search paths to include the directory
            // where the standard library has been installed
            searchPaths.Add("..\\..\\Lib");
            pythonEngine.SetSearchPaths(searchPaths);

            // Execute the script
            // We execute this script from Visual Studio
            // so the program will executed from bin\Debug or bin\Release
            Microsoft.Scripting.Hosting.ScriptSource pythonScript = 
                pythonEngine.CreateScriptSourceFromFile("..\\..\\HelloWorldBase64.py");
            pythonScript.Execute();
        }
    }
}
 Console output
Search paths:
.
C:\GitRepositories\needfulsoftwaretutorials\IronPython\CSharpIntegration\PythonS
criptExecution4\PythonScriptExecution4\bin\Debug\Lib
C:\GitRepositories\needfulsoftwaretutorials\IronPython\CSharpIntegration\PythonS
criptExecution4\PythonScriptExecution4\bin\Debug\DLLs

Original string: Hello World!
Encoded string: SGVsbG8gV29ybGQh
Decoded string: Hello World!
Press any key to continue . . .