// SPDX-License-Identifier: AGPL-3.0-or-later // Copyright (C) 2026 Karim Gabriele Varano using System; using System.IO; using Rhino; namespace DOSSIER; /// /// Geteilter Python-Script-Runner fuer Plugin-Startup (startup.py) und /// Commands (cmd/*.py). Primaer ueber Rhino.Runtime.Code-API (CPython3), /// Fallback ueber _-RunPythonScript-Command. /// internal static class PythonRunner { /// Fuehrt das Script aus. Versucht RhinoCode-API zuerst, /// faellt auf _-RunPythonScript zurueck. Labels nur fuer Logs. public static bool Run(string scriptPath, string label) { if (!File.Exists(scriptPath)) { RhinoApp.WriteLine($"[DOSSIER] {label}: Script nicht gefunden: {scriptPath}"); return false; } if (TryRunViaRhinoCode(scriptPath, label)) return true; try { RhinoApp.RunScript($"_-RunPythonScript \"{scriptPath}\"", echo: false); return true; } catch (Exception ex) { RhinoApp.WriteLine($"[DOSSIER] {label} RunScript: {ex.Message}"); return false; } } /// Wie Run, aber defern auf das naechste Idle-Event. /// Erlaubt safe Invocation aus Plugin-OnLoad oder Command-RunCommand /// (Rhino mag kein direktes _-RunPythonScript aus diesen Kontexten). public static void RunDeferred(string scriptPath, string label) { EventHandler? handler = null; handler = (sender, e) => { RhinoApp.Idle -= handler; Run(scriptPath, label); }; RhinoApp.Idle += handler; } private static bool TryRunViaRhinoCode(string scriptPath, string label) { try { var spec = new Rhino.Runtime.Code.Languages.LanguageSpec("*.*.python", "3.*"); var lang = Rhino.Runtime.Code.RhinoCode.Languages.QueryLatest(spec); if (lang == null) return false; // RhinoCode.CreateCode(text) setzt __file__/sys.path NICHT automatisch // — die DOSSIER-Scripts erwarten beides. Injizieren vorne rein. var pathLit = scriptPath.Replace("\\", "/"); var preamble = "import sys, os\n" + $"__file__ = r'{pathLit}'\n" + "sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))\n" + "sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))\n"; var code = lang.CreateCode(preamble + File.ReadAllText(scriptPath)); var ctx = new Rhino.Runtime.Code.Execution.RunContext(); code.Run(ctx); return true; } catch (Exception ex) { RhinoApp.WriteLine($"[DOSSIER] {label} RhinoCode: {ex.Message}"); return false; } } }