Skip to content

Commit 8836d3d

Browse files
authored
Handle null python traceback on clr bubbled exception (#77)
* Minor fix for null python traceback on clr bubbled exception * Fix and add unit test * Minor change * Bump version to 2.0.24
1 parent 738527d commit 8836d3d

File tree

5 files changed

+81
-7
lines changed

5 files changed

+81
-7
lines changed

src/embed_tests/TestPythonException.cs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,12 +265,81 @@ def CallThrow(self):
265265
}
266266
}
267267

268+
[Test]
269+
public void TestGetsPythonCodeInfoInStackTraceForNestedInterop()
270+
{
271+
using (Py.GIL())
272+
{
273+
dynamic testClassModule = PyModule.FromString("TestGetsPythonCodeInfoInStackTraceForNestedInterop_Module", @"
274+
from clr import AddReference
275+
AddReference(""Python.EmbeddingTest"")
276+
AddReference(""System"")
277+
278+
from Python.EmbeddingTest import *
279+
from System import Action
280+
281+
class TestPythonClass(TestPythonException.TestClass):
282+
def CallThrow(self):
283+
super().ThrowExceptionNested()
284+
285+
def GetThrowAction():
286+
return Action(CallThrow)
287+
288+
def CallThrow():
289+
TestPythonClass().CallThrow()
290+
");
291+
292+
try
293+
{
294+
var action = testClassModule.GetThrowAction();
295+
action();
296+
}
297+
catch (ClrBubbledException ex)
298+
{
299+
Assert.AreEqual("Test Exception Message", ex.InnerException.Message);
300+
301+
var pythonTracebackLines = ex.PythonTraceback.TrimEnd('\n').Split('\n').Select(x => x.Trim()).ToList();
302+
Assert.AreEqual(4, pythonTracebackLines.Count);
303+
304+
Assert.IsTrue(new[]
305+
{
306+
"File ",
307+
"fixtures\\PyImportTest\\SampleScript.py",
308+
"line 5",
309+
"in invokeMethodImpl"
310+
}.All(x => pythonTracebackLines[0].Contains(x)));
311+
Assert.AreEqual("getattr(instance, method_name)()", pythonTracebackLines[1]);
312+
313+
Assert.IsTrue(new[]
314+
{
315+
"File ",
316+
"fixtures\\PyImportTest\\SampleScript.py",
317+
"line 2",
318+
"in invokeMethod"
319+
}.All(x => pythonTracebackLines[2].Contains(x)));
320+
Assert.AreEqual("invokeMethodImpl(instance, method_name)", pythonTracebackLines[3]);
321+
}
322+
catch (Exception ex)
323+
{
324+
Assert.Fail($"Unexpected exception: {ex}");
325+
}
326+
}
327+
}
328+
268329
public class TestClass
269330
{
270331
public void ThrowException()
271332
{
272333
throw new ArgumentException("Test Exception Message");
273334
}
335+
336+
public void ThrowExceptionNested()
337+
{
338+
using var _ = Py.GIL();
339+
340+
dynamic module = Py.Import("PyImportTest.SampleScript");
341+
module.invokeMethod(this, "ThrowException");
342+
}
274343
}
275344
}
276345
}

src/perf_tests/Python.PerformanceTests.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
1414
</PackageReference>
1515
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.*" />
16-
<PackageReference Include="quantconnect.pythonnet" Version="2.0.23" GeneratePathProperty="true">
16+
<PackageReference Include="quantconnect.pythonnet" Version="2.0.24" GeneratePathProperty="true">
1717
<IncludeAssets>compile</IncludeAssets>
1818
</PackageReference>
1919
</ItemGroup>
@@ -25,7 +25,7 @@
2525
</Target>
2626

2727
<Target Name="CopyBaseline" AfterTargets="Build">
28-
<Copy SourceFiles="$(NuGetPackageRoot)quantconnect.pythonnet\2.0.23\lib\net5.0\Python.Runtime.dll" DestinationFolder="$(OutDir)baseline" />
28+
<Copy SourceFiles="$(NuGetPackageRoot)quantconnect.pythonnet\2.0.24\lib\net5.0\Python.Runtime.dll" DestinationFolder="$(OutDir)baseline" />
2929
</Target>
3030

3131
<Target Name="CopyNewBuild" AfterTargets="Build">

src/runtime/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
[assembly: InternalsVisibleTo("Python.EmbeddingTest, PublicKey=00240000048000009400000006020000002400005253413100040000110000005ffd8f49fb44ab0641b3fd8d55e749f716e6dd901032295db641eb98ee46063cbe0d4a1d121ef0bc2af95f8a7438d7a80a3531316e6b75c2dae92fb05a99f03bf7e0c03980e1c3cfb74ba690aca2f3339ef329313bcc5dccced125a4ffdc4531dcef914602cd5878dc5fbb4d4c73ddfbc133f840231343e013762884d6143189")]
55
[assembly: InternalsVisibleTo("Python.Test, PublicKey=00240000048000009400000006020000002400005253413100040000110000005ffd8f49fb44ab0641b3fd8d55e749f716e6dd901032295db641eb98ee46063cbe0d4a1d121ef0bc2af95f8a7438d7a80a3531316e6b75c2dae92fb05a99f03bf7e0c03980e1c3cfb74ba690aca2f3339ef329313bcc5dccced125a4ffdc4531dcef914602cd5878dc5fbb4d4c73ddfbc133f840231343e013762884d6143189")]
66

7-
[assembly: AssemblyVersion("2.0.23")]
8-
[assembly: AssemblyFileVersion("2.0.23")]
7+
[assembly: AssemblyVersion("2.0.24")]
8+
[assembly: AssemblyFileVersion("2.0.24")]

src/runtime/Python.Runtime.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<RootNamespace>Python.Runtime</RootNamespace>
66
<AssemblyName>Python.Runtime</AssemblyName>
77
<PackageId>QuantConnect.pythonnet</PackageId>
8-
<Version>2.0.23</Version>
8+
<Version>2.0.24</Version>
99
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
1010
<PackageLicenseFile>LICENSE</PackageLicenseFile>
1111
<RepositoryUrl>https://github.com/pythonnet/pythonnet</RepositoryUrl>

src/runtime/PythonException.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System;
22
using System.Diagnostics;
3-
using System.Linq;
43
using System.Runtime.CompilerServices;
54
using System.Runtime.ExceptionServices;
65
using System.Runtime.Serialization;
@@ -185,8 +184,14 @@ private static Exception FromPyErr(BorrowedReference typeRef, BorrowedReference
185184
exception = decodedException;
186185
}
187186

188-
if (!(exception is null))
187+
if (exception is not null)
189188
{
189+
// Return ClrBubbledExceptions when they are bubbled from Python -> C# -> Python -> C# -> ...
190+
if (exception is ClrBubbledException)
191+
{
192+
return exception;
193+
}
194+
190195
using var _ = new Py.GILState();
191196
return new ClrBubbledException(exception, TracebackToString(traceback));
192197
}

0 commit comments

Comments
 (0)