diff --git a/.gitignore b/.gitignore index bc78471..9856e5e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,9 @@ ## ## Get latest from `dotnet new gitignore` +# local python runtime +python/ + # dotenv files .env diff --git a/TOMdoptPlugin.sln b/TOMdoptPlugin.sln deleted file mode 100644 index 429f52f..0000000 --- a/TOMdoptPlugin.sln +++ /dev/null @@ -1,25 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.11.35327.3 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "doptPlugin", "doptPlugin\doptPlugin.csproj", "{A7CD5D7D-A70B-45E3-A663-2F7C7A6D041A}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A7CD5D7D-A70B-45E3-A663-2F7C7A6D041A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A7CD5D7D-A70B-45E3-A663-2F7C7A6D041A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A7CD5D7D-A70B-45E3-A663-2F7C7A6D041A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A7CD5D7D-A70B-45E3-A663-2F7C7A6D041A}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {437CE6B1-EBF0-4E0B-86AD-21EB2E9FAE74} - EndGlobalSection -EndGlobal diff --git a/dopt.TOM.sln b/dopt.TOM.sln new file mode 100644 index 0000000..ca64ec6 --- /dev/null +++ b/dopt.TOM.sln @@ -0,0 +1,41 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35327.3 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dopt.TOMTests", "dopt.TOMTests\dopt.TOMTests.csproj", "{28496580-EF8C-4D54-8FEF-BAA2E4970367}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dopt.TOM", "dopt.TOM\dopt.TOM.csproj", "{73F5A4E6-A788-4BBE-CE74-61670014CEE3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {28496580-EF8C-4D54-8FEF-BAA2E4970367}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {28496580-EF8C-4D54-8FEF-BAA2E4970367}.Debug|Any CPU.Build.0 = Debug|Any CPU + {28496580-EF8C-4D54-8FEF-BAA2E4970367}.Debug|x64.ActiveCfg = Debug|Any CPU + {28496580-EF8C-4D54-8FEF-BAA2E4970367}.Debug|x64.Build.0 = Debug|Any CPU + {28496580-EF8C-4D54-8FEF-BAA2E4970367}.Release|Any CPU.ActiveCfg = Release|Any CPU + {28496580-EF8C-4D54-8FEF-BAA2E4970367}.Release|Any CPU.Build.0 = Release|Any CPU + {28496580-EF8C-4D54-8FEF-BAA2E4970367}.Release|x64.ActiveCfg = Release|Any CPU + {28496580-EF8C-4D54-8FEF-BAA2E4970367}.Release|x64.Build.0 = Release|Any CPU + {73F5A4E6-A788-4BBE-CE74-61670014CEE3}.Debug|Any CPU.ActiveCfg = Debug|x64 + {73F5A4E6-A788-4BBE-CE74-61670014CEE3}.Debug|Any CPU.Build.0 = Debug|x64 + {73F5A4E6-A788-4BBE-CE74-61670014CEE3}.Debug|x64.ActiveCfg = Debug|x64 + {73F5A4E6-A788-4BBE-CE74-61670014CEE3}.Debug|x64.Build.0 = Debug|x64 + {73F5A4E6-A788-4BBE-CE74-61670014CEE3}.Release|Any CPU.ActiveCfg = Release|x64 + {73F5A4E6-A788-4BBE-CE74-61670014CEE3}.Release|Any CPU.Build.0 = Release|x64 + {73F5A4E6-A788-4BBE-CE74-61670014CEE3}.Release|x64.ActiveCfg = Release|x64 + {73F5A4E6-A788-4BBE-CE74-61670014CEE3}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {437CE6B1-EBF0-4E0B-86AD-21EB2E9FAE74} + EndGlobalSection +EndGlobal diff --git a/dopt.TOM/Plugin.cs b/dopt.TOM/Plugin.cs new file mode 100644 index 0000000..4d742f7 --- /dev/null +++ b/dopt.TOM/Plugin.cs @@ -0,0 +1,37 @@ +using Python.Runtime; +using System; +using static System.Net.Mime.MediaTypeNames; +using System.IO; +using System.Reflection; +using System.Dynamic; + +namespace dopt.TOM +{ + public class Plugin : SharpPython.BasePlugin + { + internal const string langMainBaseFolderName = "bin"; + internal const string langMainStopSearchFolderName = "python"; + internal const string doptTOMPluginLibraryUsage = "1"; + protected dynamic tomWrapperPipelines; + public Plugin(string runtimePath) : base(SharpPython.PyOptimLevels.O, threaded: false, runtimePath: runtimePath, verbose: true) + { + base.Initialise(); + using (Py.GIL()) + { + dynamic os = Py.Import("os"); + os.putenv("LANG_MAIN_BASE_FOLDERNAME", langMainBaseFolderName); + os.putenv("LANG_MAIN_STOP_SEARCH_FOLDERNAME", langMainStopSearchFolderName); + os.putenv("DOPT_TOM_PLUGIN_LIBRARY_USAGE", doptTOMPluginLibraryUsage); + tomWrapperPipelines = Py.Import("tom_plugin.pipeline"); + } + } + public void RunOnCSV(string identifier, string filename) + { + AssertNotDisposed(); + using (Py.GIL()) + { + tomWrapperPipelines.run_on_csv_data(identifier, filename); + } + } + } +} diff --git a/doptPlugin/doptPlugin.csproj b/dopt.TOM/dopt.TOM.csproj similarity index 62% rename from doptPlugin/doptPlugin.csproj rename to dopt.TOM/dopt.TOM.csproj index 8d812d7..032b78b 100644 --- a/doptPlugin/doptPlugin.csproj +++ b/dopt.TOM/dopt.TOM.csproj @@ -3,11 +3,12 @@ netstandard2.0 x64 - 0.1.1-beta1 + 0.1.2 + x64 - + diff --git a/dopt.TOMTests/MSTestSettings.cs b/dopt.TOMTests/MSTestSettings.cs new file mode 100644 index 0000000..ceea514 --- /dev/null +++ b/dopt.TOMTests/MSTestSettings.cs @@ -0,0 +1 @@ +[assembly: Parallelize(Scope = ExecutionScope.ClassLevel)] diff --git a/dopt.TOMTests/Tests.cs b/dopt.TOMTests/Tests.cs new file mode 100644 index 0000000..5c06f55 --- /dev/null +++ b/dopt.TOMTests/Tests.cs @@ -0,0 +1,17 @@ +namespace dopt.TOMTests +{ + using dopt.TOM; + [TestClass] + public sealed class PluginTests + { + public const string rtPath = @"A:\Arbeitsaufgaben\MOP-TOM\tom-plugin-deploy\bin"; + public const string dummyData = @"Dummy_Dataset_N_1000.csv"; + [TestMethod] + public void RunPipelineOnTestData() + { + var plugin = new Plugin(rtPath); + plugin.RunOnCSV("t123", dummyData); + plugin.Dispose(); + } + } +} diff --git a/dopt.TOMTests/dopt.TOMTests.csproj b/dopt.TOMTests/dopt.TOMTests.csproj new file mode 100644 index 0000000..5e7bdd0 --- /dev/null +++ b/dopt.TOMTests/dopt.TOMTests.csproj @@ -0,0 +1,35 @@ + + + + net48 + latest + enable + enable + true + Exe + true + + true + x64 + AnyCPU + + + + + + + + + + + + + + + + + + diff --git a/doptPlugin/Plugin.cs b/doptPlugin/Plugin.cs deleted file mode 100644 index aed371b..0000000 --- a/doptPlugin/Plugin.cs +++ /dev/null @@ -1,134 +0,0 @@ -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(); - } - } -}