[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/pythonindy/pythonnet/master/pythonnet/src/runtime/exceptions.cs [Back]  [Original]

// ==========================================================================
// This software is subject to the provisions of the Zope Public License,
// Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
// FOR A PARTICULAR PURPOSE.
// ==========================================================================

using System;
using System.Reflection;
using System.Collections;
using System.Runtime.InteropServices;


namespace Python.Runtime {

    /// 
    /// Encapsulates the Python exception APIs.
    /// 

    public class Exceptions {

	private Exceptions() {}

	//===================================================================
	// Initialization performed on startup of the Python runtime.
	//===================================================================

	internal static void Initialize() {
	    IntPtr module = Runtime.PyImport_ImportModule("exceptions");
	    Type type = typeof(Exceptions);
	    foreach (FieldInfo fi in type.GetFields(BindingFlags.Public | 
						    BindingFlags.Static)) {
		IntPtr op = Runtime.PyObject_GetAttrString(module, fi.Name);
		if (op != IntPtr.Zero) {
		    fi.SetValue(type, op);
		}
	    }
	    Runtime.Decref(module);
	    Runtime.PyErr_Clear();
	    if (Runtime.wrap_exceptions) {
		SetupExceptionHack();
	    }
	}


	//===================================================================
	// Cleanup resources upon shutdown of the Python runtime.
	//===================================================================

	internal static void Shutdown() {
	    Type type = typeof(Exceptions);
	    foreach (FieldInfo fi in type.GetFields(BindingFlags.Public | 
						    BindingFlags.Static)) {
		IntPtr op = (IntPtr)fi.GetValue(type);
		Runtime.Decref(op);
	    }
	}


	// Versions of CPython up to 2.4 do not allow exceptions to be
	// new-style classes. To get around that restriction and provide
	// a consistent user experience for programmers, we wrap managed
	// exceptions in an old-style class that (through some dont-try-
	// this-at-home hackery) delegates to the managed exception and
	// obeys the conventions of both Python and managed exceptions.

	static IntPtr ns_exc; // new-style class for System.Exception
	static IntPtr os_exc; // old-style class for System.Exception
	static Hashtable cache;

	internal static void SetupExceptionHack() {
	    ns_exc = ClassManager.GetClass(typeof(Exception)).pyHandle;
	    cache = new Hashtable();

	    string code = 
            "import exceptions\n" +
            "class Exception(exceptions.Exception):\n" +
            "    _class = None\n" +
	    "    _inner = None\n" +
            "\n" +
            "    def __init__(self, *args, **kw):\n" +
            "        inst = self.__class__._class(*args, **kw)\n" +
            "        self.__dict__['_inner'] = inst\n" +
            "        exceptions.Exception.__init__(self, *args, **kw)\n" +
            "\n" +
            "    def __getattr__(self, name, _marker=[]):\n" +
            "        inner = self.__dict__['_inner']\n" +
            "        v = getattr(inner, name, _marker)\n" +
            "        if v is not _marker:\n" +
            "            return v\n" +
            "        v = self.__dict__.get(name, _marker)\n" +
            "        if v is not _marker:\n" +
            "            return v\n" +
            "        raise AttributeError(name)\n" +
            "\n" +
            "    def __setattr__(self, name, value):\n" +
            "        inner = self.__dict__['_inner']\n" +
            "        setattr(inner, name, value)\n" +
            "\n" +
            "    def __str__(self):\n" +
            "        inner = self.__dict__.get('_inner')\n" +
            "        msg = getattr(inner, 'Message', '')\n" +
            "        st = getattr(inner, 'StackTrace', '')\n" +
            "        st = st and '\\n' + st or ''\n" +
            "        return msg + st\n" +
            "\n";

	    IntPtr dict = Runtime.PyDict_New();

	    IntPtr builtins = Runtime.PyEval_GetBuiltins();
	    Runtime.PyDict_SetItemString(dict, "__builtins__", builtins);

	    IntPtr namestr = Runtime.PyString_FromString("System");
	    Runtime.PyDict_SetItemString(dict, "__name__", namestr);
	    Runtime.Decref(namestr);

	    Runtime.PyDict_SetItemString(dict, "__file__", Runtime.PyNone);
	    Runtime.PyDict_SetItemString(dict, "__doc__", Runtime.PyNone);

	    IntPtr flag = Runtime.Py_file_input;
	    IntPtr done = Runtime.PyRun_String(code, flag, dict, dict);

	    os_exc = Runtime.PyDict_GetItemString(dict, "Exception");
	    Runtime.PyObject_SetAttrString(os_exc, "_class", ns_exc);
	    Runtime.PyErr_Clear();
	}


	internal static IntPtr GenerateExceptionClass(IntPtr real) {
	    if (real == ns_exc) {
                return os_exc;
	    }

	    IntPtr nbases = Runtime.PyObject_GetAttrString(real, "__bases__");
	    if (Runtime.PyTuple_Size(nbases) != 1) {
		throw new SystemException("Invalid __bases__");
	    }
	    IntPtr nsbase = Runtime.PyTuple_GetItem(nbases, 0);
	    Runtime.Decref(nbases);

	    IntPtr osbase = GetExceptionClassWrapper(nsbase);
            IntPtr baselist = Runtime.PyTuple_New(1);
	    Runtime.Incref(osbase);
	    Runtime.PyTuple_SetItem(baselist, 0, osbase);
	    IntPtr name = Runtime.PyObject_GetAttrString(real, "__name__");

	    IntPtr dict = Runtime.PyDict_New();
	    IntPtr mod = Runtime.PyObject_GetAttrString(real, "__module__");
	    Runtime.PyDict_SetItemString(dict, "__module__", mod);
	    Runtime.Decref(mod);

	    IntPtr subc = Runtime.PyClass_New(baselist, dict, name);
	    Runtime.Decref(baselist);
	    Runtime.Decref(dict);
	    Runtime.Decref(name);

	    Runtime.PyObject_SetAttrString(subc, "_class", real);
	    return subc;
	}

	internal static IntPtr GetExceptionClassWrapper(IntPtr real) {
	    // Given the pointer to a new-style class representing a managed
	    // exception, return an appropriate old-style class wrapper that
	    // maintains all of the expectations and delegates to the wrapped
	    // class.
	    object ob = cache[real];
	    if (ob == null) {
		IntPtr op = GenerateExceptionClass(real);
		cache[real] = op;
		return op;
	    }
	    return (IntPtr)ob;
	}

	internal static IntPtr GetExceptionInstanceWrapper(IntPtr real) {
	    // Given the pointer to a new-style class instance representing a 
	    // managed exception, return an appropriate old-style class 
	    // wrapper instance that delegates to the wrapped instance.
	    IntPtr tp = Runtime.PyObject_TYPE(real);
	    if (Runtime.PyObject_TYPE(tp) == Runtime.PyInstanceType) {
		return real;
	    }
	    // Get / generate a class wrapper, instantiate it and set its
	    // _inner attribute to the real new-style exception instance.
	    IntPtr ct = GetExceptionClassWrapper(tp);
	    IntPtr op = Runtime.PyInstance_NewRaw(ct, IntPtr.Zero);
	    IntPtr d = Runtime.PyObject_GetAttrString(op, "__dict__");
	    Runtime.PyDict_SetItemString(d, "_inner", real);
	    Runtime.Decref(d);
	    return op;
	}

	internal static IntPtr UnwrapExceptionClass(IntPtr op) {
	    // In some cases its necessary to recognize an exception *class*,
	    // and obtain the inner (wrapped) exception class. This method
	    // returns the inner class if found, or a null pointer.

	    IntPtr d = Runtime.PyObject_GetAttrString(op, "__dict__");
	    if (d == IntPtr.Zero) {
		Exceptions.Clear();
		return IntPtr.Zero;
	    }
	    IntPtr c = Runtime.PyDict_GetItemString(d, "_class");
	    Runtime.Decref(d);
	    if (c == IntPtr.Zero) {
		Exceptions.Clear();
	    }
	    return c;
	}


	/// 
	/// GetException Method
	/// 
	///
	/// 
	/// Retrieve Python exception information as a PythonException
	/// instance. The properties of the PythonException may be used
	/// to access the exception type, value and traceback info.
	/// 

	public static PythonException GetException() {
	    // TODO: implement this.
	    return null;
	}

	/// 
	/// ExceptionMatches Method
	/// 
	///
	/// 
	/// Returns true if the current Python exception matches the given
	/// Python object. This is a wrapper for PyErr_ExceptionMatches.
	/// 

	public static bool ExceptionMatches(IntPtr ob) {
	    return Runtime.PyErr_ExceptionMatches(ob) != 0;
	}

	/// 
	/// ExceptionMatches Method
	/// 
	///
	/// 
	/// Returns true if the given Python exception matches the given
	/// Python object. This is a wrapper for PyErr_GivenExceptionMatches.
	/// 

	public static bool ExceptionMatches(IntPtr exc, IntPtr ob) {
	    int i = Runtime.PyErr_GivenExceptionMatches(exc, ob);
	    return (i != 0);
	}

	/// 
	/// SetError Method
	/// 
	///
	/// 
	/// Sets the current Python exception given a native string.
	/// This is a wrapper for the Python PyErr_SetString call.
	/// 

	public static void SetError(IntPtr ob, string value) {
	    Runtime.PyErr_SetString(ob, value);
	}

	/// 
	/// SetError Method
	/// 
	///
	/// 
	/// Sets the current Python exception given a Python object.
	/// This is a wrapper for the Python PyErr_SetObject call.
	/// 

	public static void SetError(IntPtr ob, IntPtr value) {
	    Runtime.PyErr_SetObject(ob, value);
	}

	/// 
	/// SetError Method
	/// 
	///
	/// 
	/// Sets the current Python exception given a CLR exception
	/// object. The CLR exception instance is wrapped as a Python
	/// object, allowing it to be handled naturally from Python.
	/// 

	public static void SetError(Exception e) {

	    // Because delegates allow arbitrary nestings of Python calling
	    // managed calling Python calling... etc. it is possible that we
	    // might get a managed exception raised that is a wrapper for a
	    // Python exception. In that case we'd rather have the real thing.

	    PythonException pe = e as PythonException;
	    if (pe != null) {
		Runtime.PyErr_SetObject(pe.Type, pe.Value);
		return;
	    }

	    IntPtr op = CLRObject.GetInstHandle(e);

	    // XXX - hack to raise a compatible old-style exception ;(
	    if (Runtime.wrap_exceptions) {
		op = GetExceptionInstanceWrapper(op);
	    }
	    IntPtr etype = Runtime.PyObject_GetAttrString(op, "__class__");
	    Runtime.PyErr_SetObject(etype, op);
	    Runtime.Decref(etype);
	}

	/// 
	/// ErrorOccurred Method
	/// 
	///
	/// 
	/// Returns true if an exception occurred in the Python runtime.
	/// This is a wrapper for the Python PyErr_Occurred call.
	/// 

	public static bool ErrorOccurred() {
	    return Runtime.PyErr_Occurred() != 0;
	}

	/// 
	/// Clear Method
	/// 
	///
	/// 
	/// Clear any exception that has been set in the Python runtime.
	/// 

	public static void Clear() {
	    Runtime.PyErr_Clear();
	}


	//====================================================================
	// Internal helper methods for common error handling scenarios.
	//====================================================================

	internal static IntPtr RaiseTypeError(string message) {
	    Exceptions.SetError(Exceptions.TypeError, message);
	    return IntPtr.Zero;
	}


	public static IntPtr ArithmeticError;
	public static IntPtr AssertionError;
	public static IntPtr AttributeError;
	public static IntPtr DeprecationWarning;
	public static IntPtr EOFError;
	public static IntPtr EnvironmentError;
	public static IntPtr Exception;
	public static IntPtr FloatingPointError;
	public static IntPtr IOError;
	public static IntPtr ImportError;
	public static IntPtr IndentationError;
	public static IntPtr IndexError;
	public static IntPtr KeyError;
	public static IntPtr KeyboardInterrupt;
	public static IntPtr LookupError;
	public static IntPtr MemoryError;
	public static IntPtr NameError;
	public static IntPtr NotImplementedError;
	public static IntPtr OSError;
	public static IntPtr OverflowError;
	public static IntPtr OverflowWarning;
	public static IntPtr ReferenceError;
	public static IntPtr RuntimeError;
	public static IntPtr RuntimeWarning;
	public static IntPtr StandardError;
	public static IntPtr StopIteration;
	public static IntPtr SyntaxError;
	public static IntPtr SyntaxWarning;
	public static IntPtr SystemError;
	public static IntPtr SystemExit;
	public static IntPtr TabError;
	public static IntPtr TypeError;
	public static IntPtr UnboundLocalError;
	public static IntPtr UnicodeError;
	public static IntPtr UserWarning;
	public static IntPtr ValueError;
	public static IntPtr Warning;
	public static IntPtr WindowsError;
	public static IntPtr ZeroDivisionError;

    }


}

Web Proxy Viewer  |  New URL  |  Original Page