disallow runtime shutdown when the Python error indicator is set, as … · pythonnet/pythonnet@a80c685

3 files changed

lines changed

Original file line numberDiff line numberDiff line change

@@ -36,6 +36,7 @@ and other `PyObject` derived types when called from Python.

3636

details about the cause of the failure

3737

- `clr.AddReference` no longer adds ".dll" implicitly

3838

- `PyIter(PyObject)` constructor replaced with static `PyIter.GetIter(PyObject)` method

39+

- Python runtime can no longer be shut down if the Python error indicator is set, as it would have unpredictable behavior

3940

- BREAKING: Return values from .NET methods that return an interface are now automatically

4041

wrapped in that interface. This is a breaking change for users that rely on being

4142

able to access members that are part of the implementation class, but not the

Original file line numberDiff line numberDiff line change

@@ -351,6 +351,12 @@ public static void Shutdown()

351351

{

352352

return;

353353

}

354+

if (Exceptions.ErrorOccurred())

355+

{

356+

throw new InvalidOperationException(

357+

"Python error indicator is set",

358+

innerException: PythonException.PeekCurrentOrNull(out _));

359+

}

354360

// If the shutdown handlers trigger a domain unload,

355361

// don't call shutdown again.

356362

AppDomain.CurrentDomain.DomainUnload -= OnDomainUnload;

Original file line numberDiff line numberDiff line change

@@ -75,6 +75,23 @@ internal static PythonException FetchCurrentRaw()

7575

=> FetchCurrentOrNullRaw()

7676

?? throw new InvalidOperationException("No exception is set");

7777
78+

internal static Exception? PeekCurrentOrNull(out ExceptionDispatchInfo? dispatchInfo)

79+

{

80+

using var _ = new Py.GILState();

81+
82+

Runtime.PyErr_Fetch(out var type, out var value, out var traceback);

83+

Runtime.PyErr_Restore(

84+

new NewReference(type, canBeNull: true).StealNullable(),

85+

new NewReference(value, canBeNull: true).StealNullable(),

86+

new NewReference(traceback, canBeNull: true).StealNullable());

87+
88+

var err = FetchCurrentOrNull(out dispatchInfo);

89+
90+

Runtime.PyErr_Restore(type.StealNullable(), value.StealNullable(), traceback.StealNullable());

91+
92+

return err;

93+

}

94+
7895

internal static Exception? FetchCurrentOrNull(out ExceptionDispatchInfo? dispatchInfo)

7996

{

8097

dispatchInfo = null;