Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 23ec9d2

Browse files
committed
raise BadPythonDllException (internal, derived from MissingMethodException) instead of confusing TypeLoadException when PythonDLL was not configured properly
1 parent fc989d5 commit 23ec9d2

File tree

5 files changed

+60
-21
lines changed

5 files changed

+60
-21
lines changed

README.rst

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,11 @@ module:
4545
Embedding Python in .NET
4646
------------------------
4747

48-
- You must set `Runtime.PythonDLL` property or `PYTHONNET_PYDLL` environment variable
49-
starting with version 3.0, otherwise you will receive `TypeInitializationException`.
50-
Typical values are `python38.dll` (Windows), `libpython3.8.dylib` (Mac),
51-
`libpython3.8.so` (most other *nix).
48+
- You must set ``Runtime.PythonDLL`` property or ``PYTHONNET_PYDLL`` environment variable
49+
starting with version 3.0, otherwise you will receive ``BadPythonDllException``
50+
(internal, derived from ``MissingMethodException``) upon calling ``Initialize``.
51+
Typical values are ``python38.dll`` (Windows), ``libpython3.8.dylib`` (Mac),
52+
``libpython3.8.so`` (most other *nix).
5253
- All calls to python should be inside a
5354
``using (Py.GIL()) {/* Your code here */}`` block.
5455
- Import python modules using ``dynamic mod = Py.Import("mod")``, then

src/embed_tests/TestPythonEngineProperties.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public static void GetPythonPathDefault()
8181
public static void GetProgramNameDefault()
8282
{
8383
PythonEngine.Initialize();
84-
string s = PythonEngine.PythonHome;
84+
string s = PythonEngine.ProgramName;
8585

8686
Assert.NotNull(s);
8787
PythonEngine.Shutdown();

src/runtime/platform/LibraryLoader.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public IntPtr Load(string dllToLoad)
111111
{
112112
var res = WindowsLoader.LoadLibrary(dllToLoad);
113113
if (res == IntPtr.Zero)
114-
throw new DllNotFoundException($"Could not load {dllToLoad}", new Win32Exception());
114+
throw new DllNotFoundException($"Could not load {dllToLoad}.", new Win32Exception());
115115
return res;
116116
}
117117

@@ -128,7 +128,7 @@ public IntPtr GetFunction(IntPtr hModule, string procedureName)
128128

129129
var res = WindowsLoader.GetProcAddress(hModule, procedureName);
130130
if (res == IntPtr.Zero)
131-
throw new MissingMethodException($"Failed to load symbol {procedureName}", new Win32Exception());
131+
throw new MissingMethodException($"Failed to load symbol {procedureName}.", new Win32Exception());
132132
return res;
133133
}
134134

src/runtime/pythonengine.cs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,15 @@ public static string ProgramName
8686
{
8787
get
8888
{
89-
IntPtr p = Runtime.Py_GetProgramName();
89+
IntPtr p = Runtime.TryUsingDll(() => Runtime.Py_GetProgramName());
9090
return UcsMarshaler.PtrToPy3UnicodePy2String(p) ?? "";
9191
}
9292
set
9393
{
9494
Marshal.FreeHGlobal(_programName);
95-
_programName = UcsMarshaler.Py3UnicodePy2StringtoPtr(value);
95+
_programName = Runtime.TryUsingDll(
96+
() => UcsMarshaler.Py3UnicodePy2StringtoPtr(value)
97+
);
9698
Runtime.Py_SetProgramName(_programName);
9799
}
98100
}
@@ -101,14 +103,16 @@ public static string PythonHome
101103
{
102104
get
103105
{
104-
IntPtr p = Runtime.Py_GetPythonHome();
106+
IntPtr p = Runtime.TryUsingDll(() => Runtime.Py_GetPythonHome());
105107
return UcsMarshaler.PtrToPy3UnicodePy2String(p) ?? "";
106108
}
107109
set
108110
{
109111
// this value is null in the beginning
110112
Marshal.FreeHGlobal(_pythonHome);
111-
_pythonHome = UcsMarshaler.Py3UnicodePy2StringtoPtr(value);
113+
_pythonHome = Runtime.TryUsingDll(
114+
() => UcsMarshaler.Py3UnicodePy2StringtoPtr(value)
115+
);
112116
Runtime.Py_SetPythonHome(_pythonHome);
113117
}
114118
}
@@ -117,13 +121,15 @@ public static string PythonPath
117121
{
118122
get
119123
{
120-
IntPtr p = Runtime.Py_GetPath();
124+
IntPtr p = Runtime.TryUsingDll(() => Runtime.Py_GetPath());
121125
return UcsMarshaler.PtrToPy3UnicodePy2String(p) ?? "";
122126
}
123127
set
124128
{
125129
Marshal.FreeHGlobal(_pythonPath);
126-
_pythonPath = UcsMarshaler.Py3UnicodePy2StringtoPtr(value);
130+
_pythonPath = Runtime.TryUsingDll(
131+
() => UcsMarshaler.Py3UnicodePy2StringtoPtr(value)
132+
);
127133
Runtime.Py_SetPath(_pythonPath);
128134
}
129135
}

src/runtime/runtime.cs

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ internal static Version PyVersion
9393
}
9494
}
9595

96-
9796
/// <summary>
9897
/// Initialize the runtime...
9998
/// </summary>
@@ -113,7 +112,10 @@ internal static void Initialize(bool initSigs = false, ShutdownMode mode = Shutd
113112
}
114113
ShutdownMode = mode;
115114

116-
if (Py_IsInitialized() == 0)
115+
bool interpreterAlreadyInitialized = TryUsingDll(
116+
() => Py_IsInitialized() != 0
117+
);
118+
if (!interpreterAlreadyInitialized)
117119
{
118120
Py_InitializeEx(initSigs ? 1 : 0);
119121
if (PyEval_ThreadsInitialized() == 0)
@@ -787,6 +789,34 @@ internal static unsafe long Refcount(IntPtr op)
787789
return *p;
788790
}
789791

792+
/// <summary>
793+
/// Call specified function, and handle PythonDLL-related failures.
794+
/// </summary>
795+
internal static T TryUsingDll<T>(Func<T> op)
796+
{
797+
try
798+
{
799+
return op();
800+
}
801+
catch (TypeInitializationException loadFailure)
802+
{
803+
var delegatesLoadFailure = loadFailure;
804+
// failure to load Delegates type might have been the cause
805+
// of failure to load some higher-level type
806+
while (delegatesLoadFailure.InnerException is TypeInitializationException nested)
807+
{
808+
delegatesLoadFailure = nested;
809+
}
810+
811+
if (delegatesLoadFailure.InnerException is BadPythonDllException badDll)
812+
{
813+
throw badDll;
814+
}
815+
816+
throw;
817+
}
818+
}
819+
790820
/// <summary>
791821
/// Export of Macro Py_XIncRef. Use XIncref instead.
792822
/// Limit this function usage for Testing and Py_Debug builds
@@ -2270,10 +2300,6 @@ internal static void SetNoSiteFlag()
22702300
if (_PythonDll != "__Internal")
22712301
{
22722302
dllLocal = loader.Load(_PythonDll);
2273-
if (dllLocal == IntPtr.Zero)
2274-
{
2275-
throw new Exception($"Cannot load {_PythonDll}");
2276-
}
22772303
}
22782304
try
22792305
{
@@ -2617,8 +2643,8 @@ static Delegates()
26172643
}
26182644
catch (MissingMethodException e) when (libraryHandle == IntPtr.Zero)
26192645
{
2620-
throw new MissingMethodException(
2621-
"Did you forget to set Runtime.PythonDLL?" +
2646+
throw new BadPythonDllException(
2647+
"Runtime.PythonDLL was not set or does not point to a supported Python runtime DLL." +
26222648
" See https://github.com/pythonnet/pythonnet#embedding-python-in-net",
26232649
e);
26242650
}
@@ -2889,6 +2915,12 @@ static Delegates()
28892915
}
28902916
}
28912917

2918+
internal class BadPythonDllException : MissingMethodException
2919+
{
2920+
public BadPythonDllException(string message, Exception innerException)
2921+
: base(message, innerException) { }
2922+
}
2923+
28922924

28932925
public enum ShutdownMode
28942926
{

0 commit comments

Comments
 (0)