@eirannejad What is the intended workflow when updating commands in a CPython plugin. Currently it seems we have to:
Open Rhino
Open _ScriptEditor
UI > Publish active project
Load the generated .rhp
Run our test suite that runs Rhino commands (a mixture of Rhino macros and Python snippets that call Rhino commands)
Close Rhino
Delete the .rhp
Open Rhino
Open _ScriptEditor
Make code changes
UI > Publish active project
… back to 4.
Is there another way to update commands after code changes (steps 6-11) than recompiling the rhp? With the previous IronPython plugin we only had to restart Rhino and everything was up to date. We were able to have a fully automated test run from within VSCode, which allowed us to restart Rhino and use script-sync to execute our plugins’ commands. Executing the commands and not calling the Python scripts directly is important for our tests. Using the manual debug functionality from _ScriptEditor does not work for us (approx. 40 commands, many more tests).
Btw., thank you for the great work of bringing CPython to Rhino.
We solved our specific debug cycle issue with an alias hack. If anybody is interested, please find following the Python script to make command aliases from Python scripts.
Upsides:
Can be distributed automatically within an office.
Aliases can be set to a central server location where the Python scripts are located.
If 2., changes to the Python scripts reflect automatically on all user machines.
Downsides:
Aliases cannot be used within aliases. Thus the command aliases the script generates are not usable in further macros. For our use case we resolved this by using the direct RunPythonScript in all macros.
No Rhino plugin versioning. You must have your own versioning system in place.
#!/usr/bin/env python3
import os
import glob
def generate_command_aliases(scan_folder, output_file, command_prefix):
"""
Scan folder for command_prefix*.py files and generate command aliases.
Args:
scan_folder (str): Path to folder to scan for command Python files
output_file (str): Path to output command aliases file
"""
# Find all Python files starting with command_prefix
search_pattern = os.path.join(scan_folder, f"{command_prefix}*.py")
command_files = glob.glob(search_pattern)
# Sort files alphabetically for consistent output
command_files.sort()
print(f"Found {len(command_files)} {command_prefix} Python files in {scan_folder}")
# Generate command aliases
with open(output_file, 'w') as f:
for py_file in command_files:
# Convert to absolute path and normalize separators
abs_path = os.path.abspath(py_file).replace('/', '\\')
# Get filename without .py extension for the alias name
filename_no_ext = os.path.splitext(os.path.basename(py_file))[0]
alias_line = f'{filename_no_ext} -_RunPythonScript "{abs_path}"\n'
f.write(alias_line)
print(f"Added: {os.path.basename(py_file)}")
print(f"\nGenerated {output_file} with {len(command_files)} command aliases")