using Python.Runtime; using System; using static System.Net.Mime.MediaTypeNames; using System.IO; using System.Reflection; namespace doptPlugin { public class Plugin { internal const string relPathToPyDll = @".\python\python311.dll"; internal const string relPathToExtensionDlls = @".\python\DLLs"; internal const string relPathToVirtualEnv = @".\python\.venv"; internal const string relPathToPythonInit = @".\python\"; internal const string langMainBaseFolderName = "bin"; internal const string langMainStopSearchFolderName = "python"; internal const string doptTOMPluginLibraryUsage = "1"; private IntPtr _threadState; private bool _prepared = false; private bool _initialised = false; public Plugin() { PrepareEnv(); } internal void PrepareEnv() { Type t = typeof(Plugin); Assembly assembly = t.Assembly; Console.WriteLine($"Location:\n{assembly.Location}\n---\nCodeBase:\n{assembly.CodeBase}"); string assemPath = assembly.CodeBase; if (assemPath.StartsWith("file:///")) { assemPath = assemPath.Replace("file:///", ""); } string dllDir = System.IO.Path.GetDirectoryName(assemPath); Console.WriteLine($"Current DLL Dir: {dllDir}"); string pathToPyDll = Path.Combine(dllDir, relPathToPyDll); string pathToExtensionDlls = Path.Combine(dllDir, relPathToExtensionDlls); string pathToVirtualEnv = Path.Combine(dllDir, relPathToVirtualEnv); string pathToPythonInit = Path.Combine(dllDir, relPathToPythonInit); if (!File.Exists(pathToPyDll)) { throw new FileNotFoundException($"Python DLL not found at: {pathToPyDll}"); } else if (!Directory.Exists(pathToExtensionDlls)) { throw new DirectoryNotFoundException($"Python Extension Dlls not found at: {pathToExtensionDlls}"); } else if (!Directory.Exists(pathToVirtualEnv)) { throw new DirectoryNotFoundException($"Python Virtual Env not found at: {pathToVirtualEnv}"); } else if (!Directory.Exists(pathToPythonInit)) { throw new DirectoryNotFoundException($"Python base directory not found at: {pathToPythonInit}"); } // environment preparation Environment.SetEnvironmentVariable("PYTHONNET_PYDLL", pathToPyDll, EnvironmentVariableTarget.Process); Environment.SetEnvironmentVariable("LANG_MAIN_BASE_FOLDERNAME", langMainBaseFolderName, EnvironmentVariableTarget.Process); Environment.SetEnvironmentVariable("LANG_MAIN_STOP_SEARCH_FOLDERNAME", langMainStopSearchFolderName, EnvironmentVariableTarget.Process); Environment.SetEnvironmentVariable("DOPT_TOM_PLUGIN_LIBRARY_USAGE", doptTOMPluginLibraryUsage, EnvironmentVariableTarget.Process); var path = Environment.GetEnvironmentVariable("PATH").TrimEnd(';'); path = string.IsNullOrEmpty(path) ? pathToVirtualEnv : path + ";" + pathToVirtualEnv; Environment.SetEnvironmentVariable("PATH", path, EnvironmentVariableTarget.Process); Environment.SetEnvironmentVariable("PYTHONHOME", pathToVirtualEnv, EnvironmentVariableTarget.Process); Environment.SetEnvironmentVariable("PYTHONPATH", $@"{pathToPythonInit}\Lib;{pathToVirtualEnv}\Lib\site-packages;{pathToVirtualEnv}\Lib;{pathToExtensionDlls}", EnvironmentVariableTarget.Process); PythonEngine.PythonHome = pathToVirtualEnv; PythonEngine.PythonPath = Environment.GetEnvironmentVariable("PYTHONPATH", EnvironmentVariableTarget.Process); _prepared = true; } internal void Initialise() { if (!_prepared) PrepareEnv(); PythonEngine.Initialize(); _threadState = PythonEngine.BeginAllowThreads(); // release GIL for use in other threads _initialised = true; } internal void Finalise() { PythonEngine.EndAllowThreads(_threadState); /* * The shutdown method leads to a Exception because the unsafe BinaryFormatter is used. * Therefore the unsafe formatter option can be allowed temporarily. A fix is already applied, * but not yet published. * see: https://github.com/pythonnet/pythonnet/issues/2282 */ AppContext.SetSwitch("System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization", true); PythonEngine.Shutdown(); AppContext.SetSwitch("System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization", false); _initialised = false; } private void Run() // for testing purposes { if (!_initialised) Initialise(); using (Py.GIL()) { dynamic np = Py.Import("numpy"); Console.WriteLine(np.cos(np.pi * 2)); dynamic rand = Py.Import("random"); Console.WriteLine(rand.randint(1, 2)); dynamic pathlib = Py.Import("pathlib"); dynamic ret = pathlib.Path.cwd(); Console.WriteLine(ret); } Finalise(); } public void RunOnCSV(string identifier, string filename) { if (!_initialised) Initialise(); using (Py.GIL()) { dynamic tomWrapperPipeline = Py.Import("tom_plugin.pipeline"); tomWrapperPipeline.run_on_csv_data(identifier, filename); } Finalise(); } } }