X Tutup
using System; namespace Python.Runtime { /// /// Provides a managed interface to exceptions thrown by the Python /// runtime. /// public class PythonException : System.Exception { private readonly PyReferenceDecrementer _referenceDecrementer; private IntPtr _pyType = IntPtr.Zero; private IntPtr _pyValue = IntPtr.Zero; private IntPtr _pyTB = IntPtr.Zero; private string _tb = ""; private string _message = ""; private bool disposed = false; public PythonException() { _referenceDecrementer = PythonEngine.CurrentRefDecrementer; IntPtr gs = PythonEngine.AcquireLock(); Runtime.PyErr_Fetch(ref _pyType, ref _pyValue, ref _pyTB); // Those references already owned by the caller ////Runtime.XIncref(_pyType); ////Runtime.XIncref(_pyValue); ////Runtime.XIncref(_pyTB); if (_pyType != IntPtr.Zero && _pyValue != IntPtr.Zero) { string type; string message; Runtime.XIncref(_pyType); using (var pyType = new PyObject(_pyType)) using (PyObject pyTypeName = pyType.GetAttr("__name__")) { type = pyTypeName.ToString(); } Runtime.XIncref(_pyValue); using (var pyValue = new PyObject(_pyValue)) { message = pyValue.ToString(); } _message = type + " : " + message; } if (_pyTB != IntPtr.Zero) { if (_tbModule == null) { _tbModule = PythonEngine.ImportModule("traceback"); } PyObject tb_module = _tbModule; Runtime.XIncref(_pyTB); using (var pyTB = new PyObject(_pyTB)) { _tb = tb_module.InvokeMethod("format_tb", pyTB).ToString(); } } PythonEngine.ReleaseLock(gs); } private static PyObject _tbModule; // Ensure that encapsulated Python objects are decref'ed appropriately // when the managed exception wrapper is garbage-collected. ~PythonException() { Dispose(false); } /// /// Restores python error. /// public void Restore() { IntPtr gs = PythonEngine.AcquireLock(); Runtime.PyErr_Restore(_pyType, _pyValue, _pyTB); _pyType = IntPtr.Zero; _pyValue = IntPtr.Zero; _pyTB = IntPtr.Zero; PythonEngine.ReleaseLock(gs); } /// /// PyType Property /// /// /// Returns the exception type as a Python object. /// public IntPtr PyType { get { return _pyType; } } /// /// PyValue Property /// /// /// Returns the exception value as a Python object. /// public IntPtr PyValue { get { return _pyValue; } } /// /// PyTB Property /// /// /// Returns the TraceBack as a Python object. /// public IntPtr PyTB { get { return _pyTB; } } /// /// Message Property /// /// /// A string representing the python exception message. /// public override string Message { get { return _message; } } /// /// StackTrace Property /// /// /// A string representing the python exception stack trace. /// public override string StackTrace { get { return _tb; } } /// /// Dispose Method /// /// /// The Dispose method provides a way to explicitly release the /// Python objects represented by a PythonException. /// If object not properly disposed can cause AppDomain unload issue. /// See GH#397 and GH#400. /// public void Dispose() { GC.SuppressFinalize(this); Dispose(true); } protected void Dispose(bool disposing) { if (!disposed) { disposed = true; IntPtr pyTypeToDispose = _pyType; _pyType = IntPtr.Zero; IntPtr pyValueToDispose = _pyValue; _pyValue = IntPtr.Zero; IntPtr pyTBToDispose = _pyTB; _pyTB = IntPtr.Zero; if (disposing) { if (Runtime.Py_IsInitialized() > 0 && !Runtime.IsFinalizing) { IntPtr gs = PythonEngine.AcquireLock(); try { Runtime.XDecref(pyTypeToDispose); Runtime.XDecref(pyValueToDispose); // XXX Do we ever get TraceBack? // if (pyTBToDispose != IntPtr.Zero) { Runtime.XDecref(pyTBToDispose); } } finally { PythonEngine.ReleaseLock(gs); } } } else { if (pyTypeToDispose != IntPtr.Zero) { _referenceDecrementer?.ScheduleDecRef(pyTypeToDispose); } if (pyValueToDispose != IntPtr.Zero) { _referenceDecrementer?.ScheduleDecRef(pyValueToDispose); } if (pyTBToDispose != IntPtr.Zero) { _referenceDecrementer?.ScheduleDecRef(pyTBToDispose); } } } } /// /// Matches Method /// /// /// Returns true if the Python exception type represented by the /// PythonException instance matches the given exception type. /// public static bool Matches(IntPtr ob) { return Runtime.PyErr_ExceptionMatches(ob) != 0; } } }
X Tutup