/// <summary> /// Execute the Python script `update_packages.py`: using a package requirements.txt file, it will install /// needed packages and uninstall unused ones /// </summary> /// <param="requirementsFile">Path to the requirements.txt file</param> /// <param="pythonInterpreter">Path to the Python interpreter on wich we run the update packages script</param> /// <returns>Standard output of the script</returns> internal static string UpdatePackages(string requirementsFile, string pythonInterpreter = PythonSettings.kDefaultPython) { PythonRunner.EnsureInitialized(); using (Py.GIL()) { dynamic spawn_process = PythonEngine.ImportModule("unity_python.common.spawn_process"); dynamic args = new PyList(); args.append(updatePackagesScript); args.append(requirementsFile); dynamic subprocess = PythonEngine.ImportModule("subprocess"); var subprocessKwargs = new PyDict(); subprocessKwargs["stdout"] = subprocess.PIPE; subprocessKwargs["stderr"] = subprocess.PIPE; subprocessKwargs["universal_newlines"] = true.ToPython(); dynamic process = spawn_process.spawn_process_in_environment(pythonInterpreter, args, kwargs: subprocessKwargs, wantLogging: false); dynamic res = process.communicate(); (string output, string errors) = (res[0], res[1]); if (!string.IsNullOrEmpty(errors)) { var pipWarningStringBuilder = new StringBuilder(); // Split errors lines to filter them individually foreach (var line in Regex.Split(errors, "\r\n|\n|\r")) { if (IsInterestingWarning(line)) { pipWarningStringBuilder.AppendLine(line); } } if (pipWarningStringBuilder.Length > 0) { UnityEngine.Debug.LogError(pipWarningStringBuilder.ToString()); } } return(output); } }
/// <summary> /// Spawns a `python -m pip freeze` subprocess and returns its output /// </summary> /// <param="pythonInterpreter">Path to the Python interpreter on which we call pip freeze</param> /// <param="pythonPath">Override PYTHONPATH with the passed argument; no override if empty string</param> /// <returns>Standard output of the pip freeze subprocess</returns> internal static string CallPipFreeze(string pythonInterpreter = PythonSettings.kDefaultPython, string pythonPath = "") { PythonRunner.EnsureInitialized(); using (Py.GIL()) { dynamic subprocess = PythonEngine.ImportModule("subprocess"); dynamic module = PythonEngine.ImportModule("unity_python.common.spawn_process"); dynamic spawn = module.spawn_process_in_environment; dynamic args = new PyList(); args.append(new PyString("-m")); args.append(new PyString("pip")); args.append(new PyString("freeze")); var subprocessKwargs = new PyDict(); subprocessKwargs["stdout"] = subprocess.PIPE; subprocessKwargs["stderr"] = subprocess.PIPE; subprocessKwargs["universal_newlines"] = true.ToPython(); // text streams instead of bytes dynamic envOverride = new PyDict(); if (string.IsNullOrEmpty(pythonPath)) { envOverride["PYTHONPATH"] = new PyString(""); } dynamic process = spawn(pythonInterpreter, args, kwargs: subprocessKwargs, env_override: envOverride, wantLogging: false); dynamic res = process.communicate(); (string output, string errors) = (res[0], res[1]); if (errors != null && errors.Length > 0) { UnityEngine.Debug.LogError(errors); } return(output); } }
public static void ExecuteCommand(object sender, ExecutedRoutedEventArgs e, string extensionFileName) { if (sender is ListBox listBox) { using (Py.GIL()) { dynamic comics = new PyList(); foreach (var item in listBox.SelectedItems) { if (item is Comic comic) { var pyobject = comic.ToPython(); comics.append(pyobject); } } using (var scope = Py.CreateScope()) { /* * What we have right now is a python script that runs at exactly the authority of the C# code * surrounding this comment. That is too dangerous. We will create a custom object to pass to the * Python script, and retrieve the object, detect changes, and apply them to our works. * * This not only makes things safer and simpler, but also ensures that if the python script crashes, * no changes will be made to anything in the database. */ try { scope.Exec(System.IO.File.ReadAllText(extensionFileName)); dynamic extension_func = scope.Get("extension"); string result = extension_func(comics); MessageBox.Show(result); } catch (PythonException error) { MessageBox.Show("An error occured while running the extension: " + error.ToString()); } catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException) { MessageBox.Show("An error occured while running the extension: The extension must define a function extension(List[Comic]) -> str. Did you define the function wrongly?"); } } } } else { MessageBox.Show("Command execution failed! Unable to cast sender of command as ListBox"); } }