'Python.Net PythonEngine.Initialize() crashes application without throwing exception

My application (C#, VS2017) previously targeted Python 3.5.1. I have updated the system to Python 3.7.1 and have this is causing PythonEngine.Initialize() to crash the application without throwing an exception.

One internet suggestion was to set the Python env in VS, however this causes VS2017 to close when opening Python/environments. I switched to VS2019 and encountered the same issue with the stripped down code here:

using System.Windows.Forms;
using Python.Runtime;
namespace WindowsFormsApp3
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            try
            {
                PythonEngine.Initialize();
            }
            catch (Exception e)
            {
                string ex = e.ToString();
            }
        }
    }
}

Python.Net was installed successfully using:

pip install pythonnet



Solution 1:[1]

Here's my PythonNet init function.

I found that if the PythonEngine.PythonPath isn't set, the app will instantly die -- hail the power of unmanaged code. You may also need to manually set the Runtime.PythonDLL to the actual python dll you wish to load. (ie [path to python]\python38.dll)

Note that running "pip install pythonnet" only installs the ability to load & use CLR types & assemblies from Python. To embed PythonNet in a C# app, you actually don't need to install pythonnet on the Python side.

This function uses some globals set at startup.

  • Program.PythonHome -- points to the Python root folder I'm using
  • Program.ScriptsDir -- my own app python scripts dir
  • Program.PythonDll -- the main python interpreter dll
  • Program.ApplicationName -- just my own app name

I also call PythonEngine.BeginAllowThreads(); as I'm calling from multiple threads.

    public static void InitPython(Microsoft.Extensions.Logging.ILogger logger)
    {
        string py_home = Program.PythonHome;
        string py_path = $"{py_home};";

        // will be different on linux/mac
        string[] py_paths = {"DLLs", "lib", "lib/site-packages", "lib/site-packages/win32"
                , "lib/site-packages/win32/lib", "lib/site-packages/Pythonwin" };

        foreach (string p in py_paths)
        {
            py_path += $"{py_home}/{p};";
        }

        try
        {
            Runtime.PythonDLL = Program.PythonDll;
            PythonEngine.PythonPath = $"{Program.ScriptsDir};{py_path}";
            PythonEngine.PythonHome = Program.PythonHome;
            PythonEngine.ProgramName = Program.ApplicationName;
            PythonEngine.Initialize();
            PythonEngine.BeginAllowThreads();

            logger.LogInformation("Python Version: {v}, {dll}", PythonEngine.Version.Trim(), Runtime.PythonDLL);
            logger.LogInformation("Python Home: {home}", PythonEngine.PythonHome);
            logger.LogInformation("Python Path: {path}", PythonEngine.PythonPath);

        }
        catch (System.TypeInitializationException e)
        {
            throw new Exception($"FATAL, Unable to load Python, dll={Runtime.PythonDLL}", e);
        }
        catch (Exception e)
        {
            throw new Exception($"Python initialization Exception, {e.Message}", e);
        }

    }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1