Hi,
I am working on a Rhino 8 C# plugin that calls Python 3 methods at runtime. The reason for mixing languages is that we have an internal Python package with functionality I don’t want to replicate in C#.
The issue I’m running into is that the Python 3 language runtime is not initialized when my plugin loads. Specifically, RhinoCode.Languages.QueryLatest(new LanguageSpec("mcneel.pythonnet.python")) returns null until the Script Editor has been opened at least once in the session.
My current workaround is using:
RhinoApp.InvokeOnUiThread(() =>
RhinoApp.RunScript(“_ScriptEditor _Close”, false)
);
This is my current Test Command:
using Rhino;
using Rhino.Runtime.Code;
using Rhino.Runtime.Code.Execution;
using Rhino.Runtime.Code.Languages;
using System.IO;
using System.Reflection;
namespace Commands
{
public class PythonTestCommand : TrnBaseCommand
{
public override string EnglishName => “PythonTestCommand”;
protected override Rhino.Commands.Result RunCommandLogic(RhinoDoc doc)
{
// 1. Get Python 3 language
var language = RhinoCode.Languages.QueryLatest(
new LanguageSpec("mcneel.pythonnet.python")
);
if (language is null)
{
RhinoApp.WriteLine("ERROR: Python 3 language not available.");
return Rhino.Commands.Result.Failure;
}
// 2. Load embedded script and append the function call
string? pythonCode = LoadEmbeddedScript("Scripts.PythonTest.python.py");
if (pythonCode is null)
{
RhinoApp.WriteLine("ERROR: Could not load embedded Python script.");
return Rhino.Commands.Result.Failure;
}
double[] data = new double[] { 1.0, 2.5, 3.7, 4.2, 5.9 };
string dataLiteral = $"[{string.Join(", ", data)}]";
pythonCode = pythonCode + $"\nresult = run({dataLiteral})";
// 3. Create code object
var code = language.CreateCode(pythonCode);
var outputStream = new MemoryStream();
var ctx = new RunContext
{
OutputStream = outputStream
};
code.Run(ctx);
string output = System.Text.Encoding.UTF8
.GetString(outputStream.ToArray())
.Trim();
RhinoApp.WriteLine($"[PythonTest] {output}");
return Rhino.Commands.Result.Success;
}
private static string? LoadEmbeddedScript(string resourceName)
{
var assembly = Assembly.GetExecutingAssembly();
using var stream = assembly.GetManifestResourceStream(resourceName);
if (stream is null) return null;
using var reader = new StreamReader(stream);
return reader.ReadToEnd();
}
}
}
}
Can anybody point me into the right direction or provide ressources?