8000 disallow runtime shutdown when the Python error indicator is set, as … · pythonnet/pythonnet@a80c685 · GitHub
[go: up one dir, main page]

Skip to content

Commit a80c685

Browse files
authored
disallow runtime shutdown when the Python error indicator is set, as it may lead to unpredictable behavior (#1780)
1 parent ac75e0c commit a80c685

File tree

3 files changed

+24
-0
lines changed

3 files changed

+24
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
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

src/runtime/PythonEngine.cs

Lines changed: 6 additions & 0 deletions
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;

src/runtime/PythonException.cs

Lines changed: 17 additions & 0 deletions
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;

0 commit comments

Comments
 (0)
0