From 8033c04b7991ddc8ed83306d27b55bce512a926c Mon Sep 17 00:00:00 2001 From: Victor Nova Date: Tue, 28 Sep 2021 20:40:00 -0700 Subject: [PATCH] raise BadPythonDllException (internal, derived from MissingMethodException) instead of confusing TypeLoadException when PythonDLL was not configured properly --- README.rst | 9 ++-- src/embed_tests/TestPythonEngineProperties.cs | 2 +- src/runtime/platform/LibraryLoader.cs | 4 +- src/runtime/pythonengine.cs | 18 ++++--- src/runtime/runtime.cs | 48 +++++++++++++++---- 5 files changed, 60 insertions(+), 21 deletions(-) diff --git a/README.rst b/README.rst index 996bfab27..c0e4229d3 100644 --- a/README.rst +++ b/README.rst @@ -45,10 +45,11 @@ module: Embedding Python in .NET ------------------------ -- You must set `Runtime.PythonDLL` property or `PYTHONNET_PYDLL` environment variable - starting with version 3.0, otherwise you will receive `TypeInitializationException`. - Typical values are `python38.dll` (Windows), `libpython3.8.dylib` (Mac), - `libpython3.8.so` (most other *nix). +- You must set ``Runtime.PythonDLL`` property or ``PYTHONNET_PYDLL`` environment variable + starting with version 3.0, otherwise you will receive ``BadPythonDllException`` + (internal, derived from ``MissingMethodException``) upon calling ``Initialize``. + Typical values are ``python38.dll`` (Windows), ``libpython3.8.dylib`` (Mac), + ``libpython3.8.so`` (most other *nix). - All calls to python should be inside a ``using (Py.GIL()) {/* Your code here */}`` block. - Import python modules using ``dynamic mod = Py.Import("mod")``, then diff --git a/src/embed_tests/TestPythonEngineProperties.cs b/src/embed_tests/TestPythonEngineProperties.cs index 626e3c77f..ca9164a1d 100644 --- a/src/embed_tests/TestPythonEngineProperties.cs +++ b/src/embed_tests/TestPythonEngineProperties.cs @@ -81,7 +81,7 @@ public static void GetPythonPathDefault() public static void GetProgramNameDefault() { PythonEngine.Initialize(); - string s = PythonEngine.PythonHome; + string s = PythonEngine.ProgramName; Assert.NotNull(s); PythonEngine.Shutdown(); diff --git a/src/runtime/platform/LibraryLoader.cs b/src/runtime/platform/LibraryLoader.cs index e361f87e4..78bf48112 100644 --- a/src/runtime/platform/LibraryLoader.cs +++ b/src/runtime/platform/LibraryLoader.cs @@ -111,7 +111,7 @@ public IntPtr Load(string dllToLoad) { var res = WindowsLoader.LoadLibrary(dllToLoad); if (res == IntPtr.Zero) - throw new DllNotFoundException($"Could not load {dllToLoad}", new Win32Exception()); + throw new DllNotFoundException($"Could not load {dllToLoad}.", new Win32Exception()); return res; } @@ -128,7 +128,7 @@ public IntPtr GetFunction(IntPtr hModule, string procedureName) var res = WindowsLoader.GetProcAddress(hModule, procedureName); if (res == IntPtr.Zero) - throw new MissingMethodException($"Failed to load symbol {procedureName}", new Win32Exception()); + throw new MissingMethodException($"Failed to load symbol {procedureName}.", new Win32Exception()); return res; } diff --git a/src/runtime/pythonengine.cs b/src/runtime/pythonengine.cs index d7322dcc2..ece70c485 100644 --- a/src/runtime/pythonengine.cs +++ b/src/runtime/pythonengine.cs @@ -86,13 +86,15 @@ public static string ProgramName { get { - IntPtr p = Runtime.Py_GetProgramName(); + IntPtr p = Runtime.TryUsingDll(() => Runtime.Py_GetProgramName()); return UcsMarshaler.PtrToPy3UnicodePy2String(p) ?? ""; } set { Marshal.FreeHGlobal(_programName); - _programName = UcsMarshaler.Py3UnicodePy2StringtoPtr(value); + _programName = Runtime.TryUsingDll( + () => UcsMarshaler.Py3UnicodePy2StringtoPtr(value) + ); Runtime.Py_SetProgramName(_programName); } } @@ -101,14 +103,16 @@ public static string PythonHome { get { - IntPtr p = Runtime.Py_GetPythonHome(); + IntPtr p = Runtime.TryUsingDll(() => Runtime.Py_GetPythonHome()); return UcsMarshaler.PtrToPy3UnicodePy2String(p) ?? ""; } set { // this value is null in the beginning Marshal.FreeHGlobal(_pythonHome); - _pythonHome = UcsMarshaler.Py3UnicodePy2StringtoPtr(value); + _pythonHome = Runtime.TryUsingDll( + () => UcsMarshaler.Py3UnicodePy2StringtoPtr(value) + ); Runtime.Py_SetPythonHome(_pythonHome); } } @@ -117,13 +121,15 @@ public static string PythonPath { get { - IntPtr p = Runtime.Py_GetPath(); + IntPtr p = Runtime.TryUsingDll(() => Runtime.Py_GetPath()); return UcsMarshaler.PtrToPy3UnicodePy2String(p) ?? ""; } set { Marshal.FreeHGlobal(_pythonPath); - _pythonPath = UcsMarshaler.Py3UnicodePy2StringtoPtr(value); + _pythonPath = Runtime.TryUsingDll( + () => UcsMarshaler.Py3UnicodePy2StringtoPtr(value) + ); Runtime.Py_SetPath(_pythonPath); } } diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index 318c7b794..a7420f946 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -93,7 +93,6 @@ internal static Version PyVersion } } - /// /// Initialize the runtime... /// @@ -113,7 +112,10 @@ internal static void Initialize(bool initSigs = false, ShutdownMode mode = Shutd } ShutdownMode = mode; - if (Py_IsInitialized() == 0) + bool interpreterAlreadyInitialized = TryUsingDll( + () => Py_IsInitialized() != 0 + ); + if (!interpreterAlreadyInitialized) { Py_InitializeEx(initSigs ? 1 : 0); if (PyEval_ThreadsInitialized() == 0) @@ -787,6 +789,34 @@ internal static unsafe long Refcount(IntPtr op) return *p; } + /// + /// Call specified function, and handle PythonDLL-related failures. + /// + internal static T TryUsingDll(Func op) + { + try + { + return op(); + } + catch (TypeInitializationException loadFailure) + { + var delegatesLoadFailure = loadFailure; + // failure to load Delegates type might have been the cause + // of failure to load some higher-level type + while (delegatesLoadFailure.InnerException is TypeInitializationException nested) + { + delegatesLoadFailure = nested; + } + + if (delegatesLoadFailure.InnerException is BadPythonDllException badDll) + { + throw badDll; + } + + throw; + } + } + /// /// Export of Macro Py_XIncRef. Use XIncref instead. /// Limit this function usage for Testing and Py_Debug builds @@ -2270,10 +2300,6 @@ internal static void SetNoSiteFlag() if (_PythonDll != "__Internal") { dllLocal = loader.Load(_PythonDll); - if (dllLocal == IntPtr.Zero) - { - throw new Exception($"Cannot load {_PythonDll}"); - } } try { @@ -2617,8 +2643,8 @@ static Delegates() } catch (MissingMethodException e) when (libraryHandle == IntPtr.Zero) { - throw new MissingMethodException( - "Did you forget to set Runtime.PythonDLL?" + + throw new BadPythonDllException( + "Runtime.PythonDLL was not set or does not point to a supported Python runtime DLL." + " See https://github.com/pythonnet/pythonnet#embedding-python-in-net", e); } @@ -2889,6 +2915,12 @@ static Delegates() } } + internal class BadPythonDllException : MissingMethodException + { + public BadPythonDllException(string message, Exception innerException) + : base(message, innerException) { } + } + public enum ShutdownMode { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy