RhinoApp.RunScript() is not working on separate thread

Hello!

I am trying to run a Rhino.RhinoApp.RunScript() in Python3 for Rhino8 from a seperate thread with:

import Rhino
import threading

def my_func(file_path):
    result : bool = Rhino.RhinoApp.RunScript(f"-_ScriptEditor Run {py_file} ", True)
    Rhino.RhinoApp.WriteLine(f"result of command: {result}")

if __name__ == "__main__":
    thread = threading.Thread(target=my_func, args=("F:/my_file_path"))
    thread.start()

The function runs and compiles but the result is always False. Yet, if I run RhinoApp.RunScript() on main no problem.

Somebody know what am I missing on the thread?

Thanks!

Yep, RhinoApp.RunScript must be run on Rhino’s main thread.

– Dale

Hello @dale , thank you for your reply!
I see for RhinoApp.RunScript.

I tried with Rhino.Runtime.PythonScript.Create().ExecuteFile(py_file) and it does run from a thread but the only problem is that it fires IronPython instead of CPython.

Is there any callback to call the function on the main UIThread? or really any a workaround/documentation to call this script from the background thread in Python? :slight_smile:

Hi @andrea.settimi,

You might try RhinoApp.InvokeOnUiThread.

– Dale

Hello @dale ,

Thanks for the suggestion!

Indeed I did try with RhinoApp.InvokeOnUiThread but even without calling RhinoApp from it, it crashes Rhino8:

import Rhino
import threading

def run_script():
    py_file = 'F:\pysync\pyversion.py'
    # Rhino.RhinoApp.RunScript(f"-_ScriptEditor Run {py_file} ", True)  # <-- it crashes even without

def my_func(file_path):
    try:
        Rhino.RhinoApp.InvokeOnUiThread(run_script)
    except Exception as e:
        print(f"An error occurred: {e}")

if __name__ == "__main__":
    thread = threading.Thread(target=my_func, args=("F:/my_file_path"))
    thread.start()

I am aware that Rhino is not meant to be thread-safe, so thanks for the time. But maybe am I calling RhinoApp.InvokeOnUiThread in an incorrect way?

In addition, since the RhinoApp.InvokeOnUiThread wants a Delegate method (a ref to a method?), which in python does not exist I also tried to pass the function as a bound function aka lambda,

Rhino.RhinoApp.InvokeOnUiThread(lambda: self.run_script())

or a functool.partial,

import functools
...
Rhino.RhinoApp.InvokeOnUiThread(functools.partial(self.run_script))

but no chance with these neither. Rhino still crash.

Hi @andrea.settimi,

Maybe something like this?

import Rhino
import System

def AddCircle():
    script = "_Circle 0 5"
    Rhino.RhinoApp.RunScript(script, False)

def Main():
    action = System.Action(AddCircle)
    Rhino.RhinoApp.InvokeOnUiThread(action, None)
    
Main()

I’ve not tried this in V8…

– Dale

Hello @dale ,

Thanks again for the suggestion.

It does not raise an exception and it doesn’t crash (good news?). The problem is that the content of the function e.g. AddCircle() is not running, i.e. the circle is not added to the space.

For that matter even a simpler RhinoApp.WriteLine("HelloWorld") does not show the print in the V8 terminal.