Is there any hack for Python only users to build RhinoPlugin in VSCode similar to the template your shared before:
Rhino - Your First Component (Mac)
Is there any build system for Python or it is all in the end .NET or C++?
Is there any hack for Python only users to build RhinoPlugin in VSCode similar to the template your shared before:
Rhino - Your First Component (Mac)
Is there any build system for Python or it is all in the end .NET or C++?
This is a fun question.
It can be done in the Script Editor
→ Rhino - Publishing Rhino/Grasshopper Script Plugins
But in VSCode, i.e your own code editor? I don’t think we have an easy-peasy solution for what you’re asking about, but it seems like something people have probably already tried to make.
Some searching turns up the following for me
So it seems other people do want this, have made it, and have even made tooling which is handy.
If none of these felt like your cup of tea, you could certainly make your own Grasshopper plugin in C# and then create a little bit of C# code to interpret python scripts as GH Components.
These are all Grasshopper Components in your references.
And script editor seems to wrap only python scripts as C# commands without access to RhinoPlugin overrides as you would do in .NET or C++. But there is not a single case for Rhino PlugIn
for Python people.
Also, I am wondering why the infrastructure of Python is still embedded to .NET but does have its own C++ Plugin infrastructure interop.
hmm… where to start?
You want to build a Rhino Plugin entirely with python?
Sorry you linked Your First GH Component and I locked onto this
Yes exactly. Any ideas where to start?
I’m not too sure honestly .
Plugins are compiled .rhp
libraries, that’s your first hurdle.
I don’t see any reason why you couldn’t make a completely empty Rhino C# plugin and then start up a python engine and do everything from these, similar to what I mentioned before.
I’m sure you could compile Ironpython to a dll, but with all of this stuff I’m not sure whether you’d be able to debug it
I don’t quite follow what you’re saying here. The Script Editor is all .NET and python is called from here. The Rhino C++ SDK is windows only currently, so c++ would be a bit limiting I think for python.
I think this is the starting point or a problem.
.rhp is .dll which is essentially an output of visual studio project.
How would be possible to write a python code and compile as Rhino Plugin of .NET?
What happens right now, is Rhino Plugin code is written in C# and Python code is injected to the command function as an argument. But this gives a hard limit because you cannot override any Rhino Plugin Inherited Classes: Command, UserData, PlugIn
and so on.
I guess the only way is to make C# plugin and then inject Python code. But since there is currently no automation workflow from Rhino, it makes little sense to write Python code for plugins if you want to start playing with Conduits and UserData.
I have some Python code in my c# plugin. To do that I embed the Python script into the c# project and set the “Build Action” to “Embedded resource”. I create a c# file with the same name as the Python script and in the c# file I create a command class and inherit from the following class:
using System;
using System.Collections.Generic;
using System.Text;
using Rhino.Commands;
using System.Reflection;
using System.IO;
using Rhino.DocObjects;
using Rhino;
namespace Foo
{
public enum PythonEngine
{
IronPython=0,
CPython=1
}
public abstract class PythonCommand : Command
{
public PythonEngine Engine { get; set; } = PythonEngine.IronPython;
public string scriptName
{
get
{
return $"{this.GetType().Name}.py";
}
}
// get a path to extract the python script to
public string scriptPath
{
get
{
var assembly = Assembly.GetExecutingAssembly();
string asm_path = System.IO.Path.GetDirectoryName(assembly.Location);
return Path.Combine(asm_path, "python", this.scriptName);
}
}
// URI of the script within the compiled assembly
public string scriptResourceName
{
get
{
return $"{this.GetType().Namespace}.{scriptName}";
}
}
private string scriptContent;
protected static PythonCommand _instance;
public PythonCommand()
{
_instance = this;
}
public static PythonCommand Instance
{
get { return _instance; }
}
public override string EnglishName
{
get { return $"{this.GetType().Name}"; }
}
// Extract the script to disk
public bool ExtractScript()
{
try
{
var assembly = Assembly.GetExecutingAssembly();
string result;
using (Stream stream = assembly.GetManifestResourceStream(this.scriptResourceName))
using (StreamReader reader = new StreamReader(stream))
{
result = reader.ReadToEnd();
}
string scriptDir = Path.GetDirectoryName(this.scriptPath);
if (!Directory.Exists(scriptDir))
{
Directory.CreateDirectory(scriptDir);
}
File.WriteAllText(this.scriptPath, result);
return true;
}
catch (System.Exception ex)
{
return false;
}
}
// Read the script and store it's content
private bool GetScript()
{
if (!File.Exists(this.scriptPath))
{
this.ExtractScript();
}
if (File.Exists(this.scriptPath))
{
this.scriptContent = File.ReadAllText(this.scriptPath);
return true;
}
else
{
return false;
}
}
// Run the command using either the older IronPython engine or the newer CPython engine
protected override Result RunCommand(RhinoDoc doc, RunMode mode)
{
int scriptResult = 1;
if (this.GetScript())
{
if (this.Engine == PythonEngine.IronPython)
{
Rhino.Runtime.PythonScript script = Rhino.Runtime.PythonScript.Create();
script.ExecuteScript(this.scriptContent);
dynamic RunCommand = script.GetVariable("RunCommand");
scriptResult = RunCommand(mode == RunMode.Interactive);
}
else if (this.Engine == PythonEngine.CPython)
{
string command = $"_-ScriptEditor _Run \"{this.scriptPath}\"";
bool success = Rhino.RhinoApp.RunScript(command, false);
scriptResult = success ? 1 : 0;
}
if (scriptResult == 0)
{
return Result.Success;
}
else if (scriptResult == 1)
{
return Result.Cancel;
}
else
{
return Result.Failure;
}
}
else
{
Rhino.RhinoApp.WriteLine($"File {this.scriptPath} was not found");
return Result.Failure;
}
}
}
}
The c# file then is simply:
namespace Foo
{
public class MyCommandName: PythonCommand
{
}
}
The Python code gets extracted into a directory name “python” that sits next to your .rhp file.