From 6668ebf5fef1a28246d5c691bf1d05d86b25fd32 Mon Sep 17 00:00:00 2001 From: Victor Uriarte Date: Thu, 2 Mar 2017 01:24:34 -0700 Subject: [PATCH 1/2] Fix PythonEngine PYTHONHOME setter Keep memory reference & fix PY3 marshal --- src/embed_tests/TestPythonEngineProperties.cs | 25 +++++++++++++++++++ src/runtime/pythonengine.cs | 15 ++++++++++- src/runtime/runtime.cs | 6 ++--- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/embed_tests/TestPythonEngineProperties.cs b/src/embed_tests/TestPythonEngineProperties.cs index 25da158f2..c7bf0870b 100644 --- a/src/embed_tests/TestPythonEngineProperties.cs +++ b/src/embed_tests/TestPythonEngineProperties.cs @@ -105,5 +105,30 @@ public static void GetPythonHomeDefault() Assert.AreEqual(envPythonHome, enginePythonHome); PythonEngine.Shutdown(); } + + [Test] + public void SetPythonHome() + { + var pythonHome = "/dummypath/"; + + PythonEngine.PythonHome = pythonHome; + PythonEngine.Initialize(); + + Assert.AreEqual(pythonHome, PythonEngine.PythonHome); + PythonEngine.Shutdown(); + } + + [Test] + public void SetPythonHomeTwice() + { + var pythonHome = "/dummypath/"; + + PythonEngine.PythonHome = "/dummypath2/"; + PythonEngine.PythonHome = pythonHome; + PythonEngine.Initialize(); + + Assert.AreEqual(pythonHome, PythonEngine.PythonHome); + PythonEngine.Shutdown(); + } } } diff --git a/src/runtime/pythonengine.cs b/src/runtime/pythonengine.cs index 4a641e538..8a00bb39f 100644 --- a/src/runtime/pythonengine.cs +++ b/src/runtime/pythonengine.cs @@ -14,6 +14,7 @@ public class PythonEngine : IDisposable { private static DelegateManager delegateManager; private static bool initialized; + private static IntPtr _pythonHome = IntPtr.Zero; public PythonEngine() { @@ -78,7 +79,17 @@ public static string PythonHome return result ?? ""; } - set { Runtime.Py_SetPythonHome(value); } + set + { + if (_pythonHome != IntPtr.Zero) + { + Marshal.FreeHGlobal(_pythonHome); + } + _pythonHome = Runtime.IsPython3 + ? UcsMarshaler.GetInstance("").MarshalManagedToNative(value) + : Marshal.StringToHGlobalAnsi(value); + Runtime.Py_SetPythonHome(_pythonHome); + } } public static string PythonPath @@ -284,6 +295,8 @@ public static void Shutdown() { if (initialized) { + Marshal.FreeHGlobal(_pythonHome); + _pythonHome = IntPtr.Zero; Runtime.Shutdown(); initialized = false; } diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index 540e2c45c..e73ce07c3 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -694,9 +694,7 @@ internal static extern void Py_SetProgramName( internal static extern IntPtr Py_GetPythonHome(); [DllImport(PythonDll)] - internal static extern void Py_SetPythonHome( - [MarshalAs(UnmanagedType.LPWStr)] string home - ); + internal static extern void Py_SetPythonHome(IntPtr home); [DllImport(PythonDll)] internal static extern IntPtr Py_GetPath(); @@ -716,7 +714,7 @@ internal static extern void Py_SetPath( internal static extern IntPtr Py_GetPythonHome(); [DllImport(PythonDll)] - internal static extern void Py_SetPythonHome(string home); + internal static extern void Py_SetPythonHome(IntPtr home); [DllImport(PythonDll)] internal static extern IntPtr Py_GetPath(); From 321aa28ba6229bf5eea619c6d484093c16f12700 Mon Sep 17 00:00:00 2001 From: Victor Uriarte Date: Thu, 2 Mar 2017 16:40:12 -0700 Subject: [PATCH 2/2] Fix set PythonPath, set ProgramName Note on PythonPath. Its actually mapping to `Py_SetPath` which is very different from PYTHONPATH env var. There is no test on it because it should be set to real paths with libraries. Otherwise it crashes. 2nd Note. `Py_SetPath` doesn't exist on PY27. --- src/embed_tests/TestPythonEngineProperties.cs | 12 ++++++++ src/runtime/pythonengine.cs | 30 +++++++++++++++---- src/runtime/runtime.cs | 12 +++----- 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/src/embed_tests/TestPythonEngineProperties.cs b/src/embed_tests/TestPythonEngineProperties.cs index c7bf0870b..11db57b3d 100644 --- a/src/embed_tests/TestPythonEngineProperties.cs +++ b/src/embed_tests/TestPythonEngineProperties.cs @@ -130,5 +130,17 @@ public void SetPythonHomeTwice() Assert.AreEqual(pythonHome, PythonEngine.PythonHome); PythonEngine.Shutdown(); } + + [Test] + public void SetProgramName() + { + var programName = "FooBar"; + + PythonEngine.ProgramName = programName; + PythonEngine.Initialize(); + + Assert.AreEqual(programName, PythonEngine.ProgramName); + PythonEngine.Shutdown(); + } } } diff --git a/src/runtime/pythonengine.cs b/src/runtime/pythonengine.cs index 8a00bb39f..b5f609630 100644 --- a/src/runtime/pythonengine.cs +++ b/src/runtime/pythonengine.cs @@ -15,6 +15,8 @@ public class PythonEngine : IDisposable private static DelegateManager delegateManager; private static bool initialized; private static IntPtr _pythonHome = IntPtr.Zero; + private static IntPtr _programName = IntPtr.Zero; + private static IntPtr _pythonPath = IntPtr.Zero; public PythonEngine() { @@ -65,7 +67,14 @@ public static string ProgramName return result ?? ""; } - set { Runtime.Py_SetProgramName(value); } + set + { + Marshal.FreeHGlobal(_programName); + _programName = Runtime.IsPython3 + ? UcsMarshaler.GetInstance("").MarshalManagedToNative(value) + : Marshal.StringToHGlobalAnsi(value); + Runtime.Py_SetProgramName(_programName); + } } public static string PythonHome @@ -81,10 +90,7 @@ public static string PythonHome } set { - if (_pythonHome != IntPtr.Zero) - { - Marshal.FreeHGlobal(_pythonHome); - } + Marshal.FreeHGlobal(_pythonHome); _pythonHome = Runtime.IsPython3 ? UcsMarshaler.GetInstance("").MarshalManagedToNative(value) : Marshal.StringToHGlobalAnsi(value); @@ -103,7 +109,14 @@ public static string PythonPath return result ?? ""; } - set { Runtime.Py_SetPath(value); } + set + { + Marshal.FreeHGlobal(_pythonPath); + _pythonPath = Runtime.IsPython3 + ? UcsMarshaler.GetInstance("").MarshalManagedToNative(value) + : Marshal.StringToHGlobalAnsi(value); + Runtime.Py_SetPath(_pythonPath); + } } public static string Version @@ -297,6 +310,11 @@ public static void Shutdown() { Marshal.FreeHGlobal(_pythonHome); _pythonHome = IntPtr.Zero; + Marshal.FreeHGlobal(_programName); + _programName = IntPtr.Zero; + Marshal.FreeHGlobal(_pythonPath); + _pythonPath = IntPtr.Zero; + Runtime.Shutdown(); initialized = false; } diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index e73ce07c3..d47c02490 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -686,9 +686,7 @@ public static extern int Py_Main( internal static extern IntPtr Py_GetProgramName(); [DllImport(PythonDll)] - internal static extern void Py_SetProgramName( - [MarshalAs(UnmanagedType.LPWStr)] string name - ); + internal static extern void Py_SetProgramName(IntPtr name); [DllImport(PythonDll)] internal static extern IntPtr Py_GetPythonHome(); @@ -700,15 +698,13 @@ internal static extern void Py_SetProgramName( internal static extern IntPtr Py_GetPath(); [DllImport(PythonDll)] - internal static extern void Py_SetPath( - [MarshalAs(UnmanagedType.LPWStr)] string home - ); + internal static extern void Py_SetPath(IntPtr home); #elif PYTHON2 [DllImport(PythonDll)] internal static extern IntPtr Py_GetProgramName(); [DllImport(PythonDll)] - internal static extern void Py_SetProgramName(string name); + internal static extern void Py_SetProgramName(IntPtr name); [DllImport(PythonDll)] internal static extern IntPtr Py_GetPythonHome(); @@ -720,7 +716,7 @@ internal static extern void Py_SetPath( internal static extern IntPtr Py_GetPath(); [DllImport(PythonDll)] - internal static extern void Py_SetPath(string home); + internal static extern void Py_SetPath(IntPtr home); #endif [DllImport(PythonDll)]