8000 Add Format method to pythonexception · pythonnet/pythonnet@37bc2be · GitHub
[go: up one dir, main page]

Skip to content

Commit 37bc2be

Browse files
committed
Add Format method to pythonexception
Allows formatting a PythonException using traceback.format_exception
1 parent 4e5fbe0 commit 37bc2be

File tree

3 files changed

+74
-0
lines changed

3 files changed

+74
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
1313
- Added function that sets Py_NoSiteFlag to 1.
1414
- Added support for Jetson Nano.
1515
- Added support for __len__ for .NET classes that implement ICollection
16+
- Added PythonException.Format method to format exceptions the same as traceback.format_exception
1617

1718
### Changed
1819

src/embed_tests/TestPythonException.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,41 @@ public void TestPythonErrorTypeName()
5454
Assert.That(ex.PythonTypeName, Is.EqualTo("ModuleNotFoundError").Or.EqualTo("ImportError"));
5555
}
5656
}
57+
58+
[Test]
59+
public void TestPythonExceptionFormat()
60+
{
61+
try
62+
{
63+
PythonEngine.Exec("raise ValueError('Error!')");
64+
Assert.Fail("Exception should have been raised");
65+
}
66+
catch (PythonException ex)
67+
{
68+
Assert.That(ex.Format(), Does.Contain("Traceback").And.Contains("(most recent call last):").And.Contains("ValueError: Error!"));
69+
}
70+
}
71+
72+
[Test]
73+
public void TestPythonExceptionFormatNoError()
74+
{
75+
var e = new PythonException();
76+
Assert.AreEqual("Missing exception/traceback information", e.Format());
77+
}
78+
79+
[Test]
80+
public void TestPythonExceptionFormatNoTraceback()
81+
{
82+
try
83+
{
84+
var module = PythonEngine.ImportModule("really____unknown___module");
85+
Assert.Fail("Unknown module should not be loaded");
86+
}
87+
catch (PythonException ex)
88+
{
89+
// ImportError/ModuleNotFoundError do not have a traceback when not running in a script
90+
Assert.AreEqual("Missing exception/traceback information", ex.Format());
91+
}
92+
}
5793
}
5894
}

src/runtime/pythonexception.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Runtime.CompilerServices;
3+
using System.Text;
34

45
namespace Python.Runtime
56
{
@@ -145,6 +146,42 @@ public string PythonTypeName
145146
get { return _pythonTypeName; }
146147
}
147148

149+
/// <summary>
150+
/// Formats this PythonException object into a message as would be printed
151+
/// out via the Python console. See traceback.format_exception
152+
/// </summary>
153+
public string Format()
154+
{
155+
string res;
156+
IntPtr gs = PythonEngine.AcquireLock();
157+
if (_pyTB != IntPtr.Zero && _pyType != IntPtr.Zero && _pyValue != IntPtr.Zero)
158+
{
159+
Runtime.XIncref(_pyType);
160+
Runtime.XIncref(_pyValue);
161+
Runtime.XIncref(_pyTB);
162+
using (PyObject pyType = new PyObject(_pyType))
163+
using (PyObject pyValue = new PyObject(_pyValue))
164+
using (PyObject pyTB = new PyObject(_pyTB))
165+
using (PyObject tb_mod = PythonEngine.ImportModule("traceback"))
166+
{
167+
var buffer = new StringBuilder();
168+
var values = tb_mod.InvokeMethod("format_exception", pyType, pyValue, pyTB);
169+
Runtime.PyErr_Clear();
170+
foreach (PyObject val in values)
171+
{
172+
buffer.Append(val.ToString());
173+
}
174+
res = buffer.ToString();
175+
}
176+
}
177+
else
178+
{
179+
res = "Missing exception/traceback information";
180+
}
181+
PythonEngine.ReleaseLock(gs);
182+
return res;
183+
}
184+
148185
/// <summary>
149186
/// Dispose Method
150187
/// </summary>

0 commit comments

Comments
 (0)
0