11using System ;
2+ using System . IO ;
3+ using System . Linq ;
4+
25using NUnit . Framework ;
36using Python . Runtime ;
47
@@ -10,6 +13,16 @@ public class TestPythonException
1013 public void SetUp ( )
1114 {
1215 PythonEngine . Initialize ( ) ;
16+
17+ // Add scripts folder to path in order to be able to import the test modules
18+ string testPath = Path . Combine ( TestContext . CurrentContext . TestDirectory , "fixtures" ) ;
19+ TestContext . Out . WriteLine ( testPath ) ;
20+
21+ using var str = Runtime . Runtime . PyString_FromString ( testPath ) ;
22+ Assert . IsFalse ( str . IsNull ( ) ) ;
23+ BorrowedReference path = Runtime . Runtime . PySys_GetObject ( "path" ) ;
24+ Assert . IsFalse ( path . IsNull ) ;
25+ Runtime . Runtime . PyList_Append ( path , str . Borrow ( ) ) ;
1326 }
1427
1528 [ OneTimeTearDown ]
@@ -195,5 +208,69 @@ public void TestPythonException_Normalize_ThrowsWhenErrorSet()
195208 Assert . Throws < InvalidOperationException > ( ( ) => pythonException . Normalize ( ) ) ;
196209 Exceptions . Clear ( ) ;
197210 }
211+
212+ [ Test ]
213+ public void TestGetsPythonCodeInfoInStackTrace ( )
214+ {
215+ using ( Py . GIL ( ) )
216+ {
217+ dynamic testClassModule = PyModule . FromString ( "TestGetsPythonCodeInfoInStackTrace_Module" , @"
218+ from clr import AddReference
219+ AddReference(""Python.EmbeddingTest"")
220+
221+ from Python.EmbeddingTest import *
222+
223+ class TestPythonClass(TestPythonException.TestClass):
224+ def CallThrow(self):
225+ super().ThrowException()
226+ " ) ;
227+
228+ try
229+ {
230+ var instance = testClassModule . TestPythonClass ( ) ;
231+ dynamic module = Py . Import ( "PyImportTest.SampleScript" ) ;
232+ module . invokeMethod ( instance , "CallThrow" ) ;
233+ }
234+ catch ( ClrBubbledException ex )
235+ {
236+ Assert . AreEqual ( "Test Exception Message" , ex . InnerException . Message ) ;
237+
238+ var pythonTracebackLines = ex . PythonTraceback . TrimEnd ( '\n ' ) . Split ( '\n ' ) . Select ( x => x . Trim ( ) ) . ToList ( ) ;
239+ Assert . AreEqual ( 5 , pythonTracebackLines . Count ) ;
240+
241+ Assert . AreEqual ( "File \" none\" , line 9, in CallThrow" , pythonTracebackLines [ 0 ] ) ;
242+
243+ Assert . IsTrue ( new [ ]
244+ {
245+ "File " ,
246+ "fixtures\\ PyImportTest\\ SampleScript.py" ,
247+ "line 5" ,
248+ "in invokeMethodImpl"
249+ } . All ( x => pythonTracebackLines [ 1 ] . Contains ( x ) ) ) ;
250+ Assert . AreEqual ( "getattr(instance, method_name)()" , pythonTracebackLines [ 2 ] ) ;
251+
252+ Assert . IsTrue ( new [ ]
253+ {
254+ "File " ,
255+ "fixtures\\ PyImportTest\\ SampleScript.py" ,
256+ "line 2" ,
257+ "in invokeMethod"
258+ } . All ( x => pythonTracebackLines [ 3 ] . Contains ( x ) ) ) ;
259+ Assert . AreEqual ( "invokeMethodImpl(instance, method_name)" , pythonTracebackLines [ 4 ] ) ;
260+ }
261+ catch ( Exception ex )
262+ {
263+ Assert . Fail ( $ "Unexpected exception: { ex } ") ;
264+ }
265+ }
266+ }
267+
268+ public class TestClass
269+ {
270+ public void ThrowException ( )
271+ {
272+ throw new ArgumentException ( "Test Exception Message" ) ;
273+ }
274+ }
198275 }
199276}
0 commit comments