X Tutup
using System; using System.Runtime.CompilerServices; using System.Text; namespace Python.Runtime { /// /// Provides a managed interface to exceptions thrown by the Python /// runtime. /// public class PythonException : System.Exception, IDisposable { private IntPtr _pyType = IntPtr.Zero; private IntPtr _pyValue = IntPtr.Zero; private IntPtr _pyTB = IntPtr.Zero; private string _tb = ""; private string _message = ""; private string _pythonTypeName = ""; private bool disposed = false; private bool _finalized = false; public PythonException() { IntPtr gs = PythonEngine.AcquireLock(); Runtime.PyErr_Fetch(out _pyType, out _pyValue, out _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(); } _pythonTypeName = type; Runtime.XIncref(_pyValue); using (var pyValue = new PyObject(_pyValue)) { message = pyValue.ToString(); } _message = type + " : " + message; } if (_pyTB != IntPtr.Zero) { using (PyObject tb_module = PythonEngine.ImportModule("traceback")) { Runtime.XIncref(_pyTB); using (var pyTB = new PyObject(_pyTB)) { _tb = tb_module.InvokeMethod("format_tb", pyTB).ToString(); } } } PythonEngine.ReleaseLock(gs); } // Ensure that encapsulated Python objects are decref'ed appropriately // when the managed exception wrapper is garbage-collected. ~PythonException() { if (_finalized || disposed) { return; } _finalized = true; Finalizer.Instance.AddFinalizedObject(ref _pyType); Finalizer.Instance.AddFinalizedObject(ref _pyValue); Finalizer.Instance.AddFinalizedObject(ref _pyTB); } /// /// 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 + base.StackTrace; } } /// /// Python error type name. /// public string PythonTypeName { get { return _pythonTypeName; } } /// /// Formats this PythonException object into a message as would be printed /// out via the Python console. See traceback.format_exception /// public string Format() { string res; IntPtr gs = PythonEngine.AcquireLock(); try { if (_pyTB != IntPtr.Zero && _pyType != IntPtr.Zero && _pyValue != IntPtr.Zero) { IntPtr tb = _pyTB; IntPtr type = _pyType; IntPtr value = _pyValue; Runtime.XIncref(type); Runtime.XIncref(value); Runtime.XIncref(tb); Runtime.PyErr_NormalizeException(ref type, ref value, ref tb); using (PyObject pyType = new PyObject(type)) using (PyObject pyValue = new PyObject(value)) using (PyObject pyTB = new PyObject(tb)) using (PyObject tb_mod = PythonEngine.ImportModule("traceback")) { var buffer = new StringBuilder(); var values = tb_mod.InvokeMethod("format_exception", pyType, pyValue, pyTB); foreach (PyObject val in values) { buffer.Append(val.ToString()); } res = buffer.ToString(); } } else { res = StackTrace; } } finally { PythonEngine.ReleaseLock(gs); } return res; } public bool IsMatches(IntPtr exc) { return Runtime.PyErr_GivenExceptionMatches(PyType, exc) != 0; } /// /// 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() { if (!disposed) { if (Runtime.Py_IsInitialized() > 0 && !Runtime.IsFinalizing) { IntPtr gs = PythonEngine.AcquireLock(); if (_pyType != IntPtr.Zero) { Runtime.XDecref(_pyType); _pyType= IntPtr.Zero; } if (_pyValue != IntPtr.Zero) { Runtime.XDecref(_pyValue); _pyValue = IntPtr.Zero; } // XXX Do we ever get TraceBack? // if (_pyTB != IntPtr.Zero) { Runtime.XDecref(_pyTB); _pyTB = IntPtr.Zero; } PythonEngine.ReleaseLock(gs); } GC.SuppressFinalize(this); disposed = true; } } /// /// 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; } [System.Diagnostics.DebuggerHidden] public static void ThrowIfIsNull(IntPtr ob) { if (ob == IntPtr.Zero) { throw new PythonException(); } } [System.Diagnostics.DebuggerHidden] internal static void ThrowIfIsNull(BorrowedReference reference) { if (reference.IsNull) { throw new PythonException(); } } [System.Diagnostics.DebuggerHidden] public static void ThrowIfIsNotZero(int value) { if (value != 0) { throw new PythonException(); } } } }
X Tutup