0

i have recently started using pythonNet for executing scripts from Csharp, on an algorithm i was doing in csharp up until now, it works pretty well:

using (Py.GIL())
{
    PythonEngine.Initialize();
    using (var scope = Py.CreateScope())
    {

        string code = File.ReadAllText(fileName);
        var scriptCompiled = PythonEngine.Compile(code, "Analyze.py");
        scope.Execute(scriptCompiled);
        dynamic func = scope.Get("predictFromData");


        PyList Pydata = new PyList(data.ToPython());
        PyTuple rettp = new PyTuple(func(Pydata));


        PyList pyIndexList = new PyList(rettp[0]);

        foreach (PyObject intobj in pyIndexList)
        {
            indexList.Add(intobj.As<int>());
        }

    }

}

But i'd like to know if there is a way to check if the code can be executed before actually running it, since it works with compiled code, and since PythonNet does require an external python installation to see if every modules are here ect... And then switch back to my previous csharp algorithm if it is not possible in python.

For now i'm thinking about simply executing a python unit test importing modules and testing functions with dummy values and returning exceptions and units tests values to csharp code, but i'd prefer a cleaner way if anyone has an idea. Cheers.

1 Answers1

1

There are few things you can check here:

first is to see if Python code has correct syntax, it can be done with the code like this:

public static IReadOnlyList<ScriptCompilationDiagnostic> CheckErrors(ScriptEngine engine, string script, string fileName, RunFlagType mode)
        {
            try
            {
                PythonEngine.Compile(script, fileName, mode);
            }
            catch (PythonException e)
            {
                dynamic error = e.Value;

                return new[]
                {
                    new ScriptCompilationDiagnostic
                    {
                        Kind = ScriptCompilationDiagnosticKind.Error,
                        Line = error.lineno - 1,
                        Column = error.offset - 1,
                        Message = error.msg,
                        Code = error.text,
                        FileName = error.filename,
                    },
                };
            }

            return new ScriptCompilationDiagnostic[0];
        }

second is that you can check if Python is installed on a target machine, with the code like this:

var pythonHome = TryGetFullPathFromPathEnvironmentVariable("python.exe");
    
private static string? TryGetFullPathFromPathEnvironmentVariable(string fileName)
{
    if (fileName.Length >= MAXPATH)
        throw new ArgumentException($"The executable name '{fileName}' must have less than {MAXPATH} characters.", nameof(fileName));
    
    var sb = new StringBuilder(fileName, MAXPATH);
    return PathFindOnPath(sb, null) ? sb.ToString() : null;
}
    
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode, SetLastError = false)]
private static extern bool PathFindOnPath([In, Out] StringBuilder pszFile, [In] string[]? ppszOtherDirs);

If your script is using third-party modules, you may check that they're installed as well:

public bool IsModuleInstalled(string module)
{
    string moduleDir = Path.Combine(PythonHome, "Lib", "site-packages", module);
    return Directory.Exists(moduleDir) && File.Exists(Path.Combine(moduleDir, "__init__.py"));
}

Please note that Python.NET does not officially support the latest Python version 3.9, so alternatively you can distribute and install embedded python with your application from here:

https://www.python.org/ftp/python/3.7.3/

alongside with all required third-party modules as wheels.

We use this approach in our AlterNET Studio product to check if Python is installed for our Python debugger based on Debug Adapter Protocol, and install embedded Python with wheels for our Python.NET based scripter/debugger.

Dmitry
  • 61
  • 3