diff --git a/src/runtime/clrobject.cs b/src/runtime/clrobject.cs index 351c7c51b..3fc29bde2 100644 --- a/src/runtime/clrobject.cs +++ b/src/runtime/clrobject.cs @@ -30,6 +30,9 @@ internal CLRObject(Object ob, IntPtr tp) : base() this.pyHandle = py; this.gcHandle = gc; inst = ob; + + // Fix the BaseException args slot if wrapping a CLR exception + Exceptions.SetArgs(py); } diff --git a/src/runtime/converter.cs b/src/runtime/converter.cs index 2737046a0..ef3aa3e18 100644 --- a/src/runtime/converter.cs +++ b/src/runtime/converter.cs @@ -156,20 +156,7 @@ internal static IntPtr ToPython(Object value, Type type) switch (tc) { case TypeCode.Object: - result = CLRObject.GetInstHandle(value, type); - - // XXX - hack to make sure we convert new-style class based - // managed exception instances to wrappers ;( - if (Runtime.wrap_exceptions) - { - Exception e = value as Exception; - if (e != null) - { - return Exceptions.GetExceptionInstanceWrapper(result); - } - } - - return result; + return CLRObject.GetInstHandle(value, type); case TypeCode.String: return Runtime.PyUnicode_FromString((string)value); @@ -283,36 +270,6 @@ internal static bool ToManagedValue(IntPtr value, Type obType, ManagedType mt = ManagedType.GetManagedObject(value); result = null; - // XXX - hack to support objects wrapped in old-style classes - // (such as exception objects). - if (Runtime.wrap_exceptions) - { - if (mt == null) - { - if (Runtime.PyObject_IsInstance( - value, Exceptions.Exception - ) > 0) - { - IntPtr p = Runtime.PyObject_GetAttrString(value, "_inner"); - if (p != IntPtr.Zero) - { - // This is safe because we know that the __dict__ of - // value holds a reference to _inner. - value = p; - Runtime.XDecref(p); - mt = ManagedType.GetManagedObject(value); - } - } - IntPtr c = Exceptions.UnwrapExceptionClass(value); - if ((c != IntPtr.Zero) && (c != value)) - { - value = c; - Runtime.XDecref(c); - mt = ManagedType.GetManagedObject(value); - } - } - } - if (mt != null) { if (mt is CLRObject) diff --git a/src/runtime/exceptions.cs b/src/runtime/exceptions.cs index f95f177e2..ec1b82175 100644 --- a/src/runtime/exceptions.cs +++ b/src/runtime/exceptions.cs @@ -23,7 +23,6 @@ internal ExceptionClassObject(Type tp) : base(tp) { } -#if (PYTHON25 || PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35) internal static Exception ToException(IntPtr ob) { CLRObject co = GetManagedObject(ob) as CLRObject; @@ -56,76 +55,12 @@ internal static Exception ToException(IntPtr ob) { message = e.Message; } - if ((e.StackTrace != null) && (e.StackTrace != String.Empty)) + if (!string.IsNullOrEmpty(e.StackTrace)) { message = message + "\n" + e.StackTrace; } return Runtime.PyUnicode_FromString(message); } - - //==================================================================== - // Exception __repr__ implementation. - //==================================================================== - - public static IntPtr tp_repr(IntPtr ob) - { - Exception e = ToException(ob); - if (e == null) - { - return Exceptions.RaiseTypeError("invalid object"); - } - string name = e.GetType().Name; - string message; - if (e.Message != String.Empty) - { - message = String.Format("{0}('{1}',)", name, e.Message); - } - else - { - message = String.Format("{0}()", name); - } - return Runtime.PyUnicode_FromString(message); - } - - //==================================================================== - // Exceptions __getattribute__ implementation. - // handles Python's args and message attributes - //==================================================================== - - public static IntPtr tp_getattro(IntPtr ob, IntPtr key) - { - if (!Runtime.PyString_Check(key)) - { - Exceptions.SetError(Exceptions.TypeError, "string expected"); - return IntPtr.Zero; - } - - string name = Runtime.GetManagedString(key); - if (name == "args") - { - Exception e = ToException(ob); - IntPtr args; - if (e.Message != String.Empty) - { - args = Runtime.PyTuple_New(1); - IntPtr msg = Runtime.PyUnicode_FromString(e.Message); - Runtime.PyTuple_SetItem(args, 0, msg); - } - else - { - args = Runtime.PyTuple_New(0); - } - return args; - } - - if (name == "message") - { - return ExceptionClassObject.tp_str(ob); - } - - return Runtime.PyObject_GenericGetAttr(ob, key); - } -#endif // (PYTHON25 || PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35) } /// @@ -173,10 +108,6 @@ internal static void Initialize() } } Runtime.PyErr_Clear(); - if (Runtime.wrap_exceptions) - { - SetupExceptionHack(); - } } @@ -204,6 +135,36 @@ internal static void Shutdown() } } + /// + /// Set the 'args' slot on a python exception object that wraps + /// a CLR exception. This is needed for pickling CLR exceptions as + /// BaseException_reduce will only check the slots, bypassing the + /// __getattr__ implementation, and thus dereferencing a NULL + /// pointer. + /// + /// A CLR exception + /// The python object wrapping + internal static void SetArgs(IntPtr ob) + { + var e = ExceptionClassObject.ToException(ob); + if (e == null) + return; + + IntPtr args; + if (!string.IsNullOrEmpty(e.Message)) + { + args = Runtime.PyTuple_New(1); + var msg = Runtime.PyUnicode_FromString(e.Message); + Runtime.PyTuple_SetItem(args, 0, msg); + } + else + { + args = Runtime.PyTuple_New(0); + } + + Marshal.WriteIntPtr(ob, ExceptionOffset.args, args); + } + /// /// Shortcut for (pointer == NULL) -> throw PythonException /// @@ -228,210 +189,6 @@ internal unsafe static void ErrorOccurredCheck(IntPtr pointer) } } - // 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. - - /// - /// Conditionally initialized variables! - /// - static IntPtr ns_exc; // new-style class for System.Exception - - static IntPtr os_exc; // old-style class for System.Exception - static Hashtable cache; - - /// - /// the lines - /// // XXX - hack to raise a compatible old-style exception ;( - /// if (Runtime.wrap_exceptions) { - /// CallOneOfTheseMethods(); - /// - /// - 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" + - " #@property\n" + - " def message(self):\n" + - " return self.Message\n" + - " message = property(message)\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" + - " def __repr__(self):\n" + - " inner = self.__dict__.get('_inner')\n" + - " msg = getattr(inner, 'Message', '')\n" + - " name = self.__class__.__name__\n" + - " return '%s(\\'%s\\',)' % (name, msg) \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.XDecref(namestr); - - Runtime.PyDict_SetItemString(dict, "__file__", Runtime.PyNone); - Runtime.PyDict_SetItemString(dict, "__doc__", Runtime.PyNone); - - IntPtr flag = Runtime.Py_file_input; - IntPtr result = Runtime.PyRun_String(code, flag, dict, dict); - Exceptions.ErrorCheck(result); - Runtime.XDecref(result); - - 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.XDecref(nbases); - - IntPtr osbase = GetExceptionClassWrapper(nsbase); - IntPtr baselist = Runtime.PyTuple_New(1); - Runtime.XIncref(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.XDecref(mod); - - IntPtr subc = Runtime.PyClass_New(baselist, dict, name); - Runtime.XDecref(baselist); - Runtime.XDecref(dict); - Runtime.XDecref(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); - Exceptions.ErrorCheck(ct); - IntPtr op = Runtime.PyInstance_NewRaw(ct, IntPtr.Zero); - Exceptions.ErrorCheck(op); - IntPtr d = Runtime.PyObject_GetAttrString(op, "__dict__"); - Exceptions.ErrorCheck(d); - Runtime.PyDict_SetItemString(d, "_inner", real); - Runtime.XDecref(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.XDecref(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 /// @@ -509,12 +266,6 @@ public static void SetError(Exception e) } 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.XDecref(etype); diff --git a/src/runtime/interop.cs b/src/runtime/interop.cs index f5fbe74b4..7288ff58c 100644 --- a/src/runtime/interop.cs +++ b/src/runtime/interop.cs @@ -89,41 +89,35 @@ static ObjectOffset() public static int magic(IntPtr ob) { -#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35) if ((Runtime.PyObject_TypeCheck(ob, Exceptions.BaseException) || (Runtime.PyType_Check(ob) && Runtime.PyType_IsSubtype(ob, Exceptions.BaseException)))) { return ExceptionOffset.ob_data; } -#endif return ob_data; } public static int DictOffset(IntPtr ob) { -#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35) if ((Runtime.PyObject_TypeCheck(ob, Exceptions.BaseException) || (Runtime.PyType_Check(ob) && Runtime.PyType_IsSubtype(ob, Exceptions.BaseException)))) { return ExceptionOffset.ob_dict; } -#endif return ob_dict; } public static int Size(IntPtr ob) { -#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35) if ((Runtime.PyObject_TypeCheck(ob, Exceptions.BaseException) || (Runtime.PyType_Check(ob) && Runtime.PyType_IsSubtype(ob, Exceptions.BaseException)))) { return ExceptionOffset.Size(); } -#endif #if (Py_DEBUG) return 6 * IntPtr.Size; #else - return 4*IntPtr.Size; + return 4 * IntPtr.Size; #endif } @@ -137,7 +131,6 @@ public static int Size(IntPtr ob) private static int ob_data; } -#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35) [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] internal class ExceptionOffset { @@ -161,15 +154,21 @@ public static int Size() // (start after PyObject_HEAD) public static int dict = 0; public static int args = 0; +#if (PYTHON25 || PYTHON26 || PYTHON27) + public static int message = 0; +#elif (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35) public static int traceback = 0; public static int context = 0; public static int cause = 0; +#if !PYTHON32 + public static int suppress_context = 0; +#endif +#endif // extra c# data public static int ob_dict; public static int ob_data; } -#endif #if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35) diff --git a/src/runtime/managedtype.cs b/src/runtime/managedtype.cs index 98e9b1c2c..782865f93 100644 --- a/src/runtime/managedtype.cs +++ b/src/runtime/managedtype.cs @@ -41,20 +41,6 @@ internal static ManagedType GetManagedObject(IntPtr ob) GCHandle gc = (GCHandle)op; return (ManagedType)gc.Target; } - - // In certain situations, we need to recognize a wrapped - // exception class and be willing to unwrap the class :( - - if (Runtime.wrap_exceptions) - { - IntPtr e = Exceptions.UnwrapExceptionClass(ob); - if ((e != IntPtr.Zero) && (e != ob)) - { - ManagedType m = GetManagedObject(e); - Runtime.XDecref(e); - return m; - } - } } return null; } diff --git a/src/runtime/moduleobject.cs b/src/runtime/moduleobject.cs index 84690215f..87e3ed2f1 100644 --- a/src/runtime/moduleobject.cs +++ b/src/runtime/moduleobject.cs @@ -202,20 +202,6 @@ public void LoadNames() if (m == null) { ManagedType attr = this.GetAttribute(name, true); - if (Runtime.wrap_exceptions) - { - if (attr is ExceptionClassObject) - { - ExceptionClassObject c = attr as ExceptionClassObject; - if (c != null) - { - IntPtr p = attr.pyHandle; - IntPtr r = Exceptions.GetExceptionClassWrapper(p); - Runtime.PyDict_SetItemString(dict, name, r); - Runtime.XIncref(r); - } - } - } } } } @@ -307,26 +293,6 @@ public static IntPtr tp_getattro(IntPtr ob, IntPtr key) return IntPtr.Zero; } - // XXX - hack required to recognize exception types. These types - // may need to be wrapped in old-style class wrappers in versions - // of Python where new-style classes cannot be used as exceptions. - - if (Runtime.wrap_exceptions) - { - if (attr is ExceptionClassObject) - { - ExceptionClassObject c = attr as ExceptionClassObject; - if (c != null) - { - IntPtr p = attr.pyHandle; - IntPtr r = Exceptions.GetExceptionClassWrapper(p); - Runtime.PyDict_SetItemString(self.dict, name, r); - Runtime.XIncref(r); - return r; - } - } - } - Runtime.XIncref(attr.pyHandle); return attr.pyHandle; } diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index 95ead8b59..6c9087169 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -212,7 +212,6 @@ public class Runtime internal static Object IsFinalizingLock = new Object(); internal static bool IsFinalizing = false; - internal static bool wrap_exceptions; internal static bool is32bit; /// @@ -332,25 +331,6 @@ internal static void Initialize() #endif #endif - - // Determine whether we need to wrap exceptions for versions of - // of the Python runtime that do not allow new-style classes to - // be used as exceptions (Python versions 2.4 and lower). - -#if (PYTHON25 || PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35) - wrap_exceptions = false; -#else - IntPtr m = PyImport_ImportModule("exceptions"); - Exceptions.ErrorCheck(m); - op = Runtime.PyObject_GetAttrString(m, "Exception"); - Exceptions.ErrorCheck(op); - if (Runtime.PyObject_TYPE(op) == PyClassType) { - wrap_exceptions = true; - } - Runtime.XDecref(op); - Runtime.XDecref(m); -#endif - // Initialize modules that depend on the runtime class. AssemblyManager.Initialize(); PyCLRMetaType = MetaType.Initialize(); diff --git a/src/runtime/typemanager.cs b/src/runtime/typemanager.cs index fcf23a07d..ecac9203c 100644 --- a/src/runtime/typemanager.cs +++ b/src/runtime/typemanager.cs @@ -128,25 +128,21 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType) // XXX Hack, use a different base class for System.Exception // Python 2.5+ allows new style class exceptions but they *must* // subclass BaseException (or better Exception). -#if (PYTHON25 || PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35) if (typeof(System.Exception).IsAssignableFrom(clrType)) { - ob_size = ObjectOffset.Size(Exceptions.BaseException); - tp_dictoffset = ObjectOffset.DictOffset(Exceptions.BaseException); + ob_size = ObjectOffset.Size(Exceptions.Exception); + tp_dictoffset = ObjectOffset.DictOffset(Exceptions.Exception); } if (clrType == typeof(System.Exception)) { base_ = Exceptions.Exception; - Runtime.XIncref(base_); } - else -#endif - if (clrType.BaseType != null) - { - ClassBase bc = ClassManager.GetClass(clrType.BaseType); - base_ = bc.pyHandle; - } + else if (clrType.BaseType != null) + { + ClassBase bc = ClassManager.GetClass(clrType.BaseType); + base_ = bc.pyHandle; + } IntPtr type = AllocateTypeObject(name); diff --git a/src/tests/test_exceptions.py b/src/tests/test_exceptions.py index 4b6386447..892d6f062 100644 --- a/src/tests/test_exceptions.py +++ b/src/tests/test_exceptions.py @@ -6,11 +6,6 @@ unicode = str -# Note: all of these tests are known to fail because Python currently -# doesn't allow new-style classes to be used as exceptions. I'm leaving -# the tests in place in to document 'how it ought to work' in the hopes -# that they'll all pass one day... - class ExceptionTests(unittest.TestCase): """Test exception support.""" @@ -300,14 +295,15 @@ def testPythonCompatOfManagedExceptions(self): msg = "A simple message" e = OverflowException(msg) - self.assertEqual(e.message, msg) - self.assertTrue(isinstance(e.message, unicode)) # ??? self.assertEqual(str(e), msg) self.assertEqual(unicode(e), msg) self.assertEqual(e.args, (msg,)) self.assertTrue(isinstance(e.args, tuple)) - self.assertEqual(repr(e), "OverflowException('A simple message',)") + if six.PY2: + self.assertEqual(repr(e), "OverflowException(u'A simple message',)") + else: + self.assertEqual(repr(e), "OverflowException('A simple message',)") def testExceptionIsInstanceOfSystemObject(self): """Test behavior of isinstance(, System.Object).""" @@ -336,6 +332,19 @@ def testExceptionIsInstanceOfSystemObject(self): else: self.assertFalse(isinstance(o, Object)) + def testPicklingExceptions(self): + from System import Exception + try: + import cPickle as pickle + except ImportError: + import pickle + + exc = Exception("test") + dumped = pickle.dumps(exc) + loaded = pickle.loads(dumped) + + self.assertEqual(exc.args, loaded.args) + def test_suite(): return unittest.makeSuite(ExceptionTests) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy