Template for Python Grasshopper Plug-in with CI/CD

Hello Rh/Gh Pythonners,

I just wanted to share with you our template here at IBOIS, EPFL to develop and distribute Python plug-ins in Grasshopper, here’s a full example of a plug-in: diffCheck.

This template is building on top of the beautifull ghcomponentizer from Compas where you basically write .ghuser objects linking to it some metadata, and icons. The enormous advantage of this approach is that it’s CI friendly and multiple people can work and distribute plug-ins professionnally.

To improve on this, we add a support and distribution of a PyPi package with it so that the biggest of the source code is stored in a PyPI repo and can be developed as such. We propose an action that tags the code each time there is a new release with a flag readable by the Rhino Python interpreter (i.e. r:diffCheck==1.1.0). This is then pushed to the yak server and the user just need to download the plug-in via the yak manager and the new releases will be automatically distributed.

Hence, developers can work with modules and the user has a one-click installation. Try it!. This layout allows to have automatic Sphinx documentation for gh components :love_you_gesture: !

df_shcs_1g_opti

Here’s a schematic of our template:

→ here’s GitHub CI: diffCheck/.github/workflows at main · diffCheckOrg/diffCheck · GitHub
→ the GitHub repo: GitHub - diffCheckOrg/diffCheck: diffCheck is a CAD-integrated tool for evaluating digital timber fabrication processes.

Have a look at [diffCheck repo] and tell us what you think, we are curious to hear about improvements and contribute to the (CI-friendly) gh pythonner community! :snake:

Great stuff. Are you able to test the plug in, within Grasshopper, within CI? I’ve figured out how to do this locally, but not in a Github Action, even with Rhino Compute.

That’s what we are trying to do now but with the new CIs out there for automatically installing Rhino (and caching it) there should not be much work to do. How do you do it locally @James_Parrott if I can ask?

On our side we were thinking using the new RhinoCode to run as a headless script with something like this to test each component and mocking the input/outputs:

But I havn’t try it yet this approach…

How do you do it locally

I still haven’t figured out how to use Rhino Compute to just run a .gh file!
So I wrote my own elaborate solution. It used a bit of code outside Rhino, that launches Rhino/Grasshopper and my .gh file, and captures the output from a test runner in a Python component, inside of Grasshopper.

Rhino already has a CLI. I used that to launch a .gh file containing a Python component, that launches the tests. After the testing is finished, it calls a function I figured out with Dale’s help to close down Rhino. Rhino’s CLI is actually called in a Python subprocess; the parent process goes on to spin up a simple light weight UDP server on localhost, and print everything it receives to stdout/stderr, and shut down on a special string. The output from the tests within the Grasshopper Python test runner component is captured(*), and sent to the UDP server.

I mocked placing .ghuser components and certain others on the canvas and connecting their inputs too!

It’s pretty experimental, and I haven;t used it in quite a few months, so I’m sure there are rough edges:

(*)I’d’ve liked to have used PyTest, but the core unittest library provides TextTestRunner which can be passed any custom output stream (file like object).