From 2b167afc38e8bcad1eed6c56d2651d1479a26b3b Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Tue, 8 Nov 2016 09:40:39 +0100 Subject: [PATCH 1/7] Remove Python <2.5 exception wrapping. --- src/runtime/converter.cs | 45 +------- src/runtime/exceptions.cs | 216 ------------------------------------ src/runtime/managedtype.cs | 14 --- src/runtime/moduleobject.cs | 34 ------ src/runtime/runtime.cs | 20 ---- src/runtime/typemanager.cs | 18 ++- 6 files changed, 8 insertions(+), 339 deletions(-) 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..1652ad794 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; @@ -125,7 +124,6 @@ public static IntPtr tp_getattro(IntPtr ob, IntPtr key) return Runtime.PyObject_GenericGetAttr(ob, key); } -#endif // (PYTHON25 || PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35) } /// @@ -173,10 +171,6 @@ internal static void Initialize() } } Runtime.PyErr_Clear(); - if (Runtime.wrap_exceptions) - { - SetupExceptionHack(); - } } @@ -228,210 +222,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 +299,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/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); From 82fdc393fcfc1c20df297578f37f513e2448c2b8 Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Tue, 8 Nov 2016 10:52:07 +0100 Subject: [PATCH 2/7] Fix crashes when trying to pickle CLR exceptions. The "args" slot of BaseException was not filled, instead we provided the args through our __getattr__ implementation. This fails in BaseException_reduce which depends on "args" being not NULL. We fix this by explicitly setting the "args" slot on all CLR exception objects on creation. This also makes tp_repr obsolete. --- src/runtime/clrobject.cs | 3 ++ src/runtime/exceptions.cs | 54 ++++++++++++++++++++---------------- src/tests/test_exceptions.py | 15 ++++++---- 3 files changed, 43 insertions(+), 29 deletions(-) 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/exceptions.cs b/src/runtime/exceptions.cs index 1652ad794..4026ba427 100644 --- a/src/runtime/exceptions.cs +++ b/src/runtime/exceptions.cs @@ -62,30 +62,6 @@ internal static Exception ToException(IntPtr ob) 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 @@ -198,6 +174,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 (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); + } + + Marshal.WriteIntPtr(ob, ExceptionOffset.args, args); + } + /// /// Shortcut for (pointer == NULL) -> throw PythonException /// diff --git a/src/tests/test_exceptions.py b/src/tests/test_exceptions.py index 4b6386447..238ead1c6 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.""" @@ -336,6 +331,16 @@ def testExceptionIsInstanceOfSystemObject(self): else: self.assertFalse(isinstance(o, Object)) + def testPicklingExceptions(self): + from System import Exception + import pickle + + exc = Exception("test") + dumped = pickle.dumps(exc) + loaded = pickle.loads(dumped) + + self.assertEqual(repr(exc), repr(loaded)) + def test_suite(): return unittest.makeSuite(ExceptionTests) From d2bfa49952583deb95564a7e032b1f0c8d26a544 Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Tue, 8 Nov 2016 12:25:22 +0100 Subject: [PATCH 3/7] Fix Python 2 compatibility. --- src/runtime/interop.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) 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) From 1a46d0e9397f5e890010ea807e48769edaf14625 Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Tue, 8 Nov 2016 14:48:57 +0100 Subject: [PATCH 4/7] Remove access to obsolete message attribute. --- src/runtime/exceptions.cs | 45 +++------------------------------------ 1 file changed, 3 insertions(+), 42 deletions(-) diff --git a/src/runtime/exceptions.cs b/src/runtime/exceptions.cs index 4026ba427..ec1b82175 100644 --- a/src/runtime/exceptions.cs +++ b/src/runtime/exceptions.cs @@ -55,51 +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); } - - //==================================================================== - // 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); - } } /// @@ -190,10 +151,10 @@ internal static void SetArgs(IntPtr ob) return; IntPtr args; - if (e.Message != String.Empty) + if (!string.IsNullOrEmpty(e.Message)) { args = Runtime.PyTuple_New(1); - IntPtr msg = Runtime.PyUnicode_FromString(e.Message); + var msg = Runtime.PyUnicode_FromString(e.Message); Runtime.PyTuple_SetItem(args, 0, msg); } else From 54868eccc080d7b3c566266b5b0fa9659a09b557 Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Tue, 8 Nov 2016 14:57:32 +0100 Subject: [PATCH 5/7] Fix the tests. --- src/tests/test_exceptions.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tests/test_exceptions.py b/src/tests/test_exceptions.py index 238ead1c6..818837bd6 100644 --- a/src/tests/test_exceptions.py +++ b/src/tests/test_exceptions.py @@ -295,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).""" @@ -339,7 +340,7 @@ def testPicklingExceptions(self): dumped = pickle.dumps(exc) loaded = pickle.loads(dumped) - self.assertEqual(repr(exc), repr(loaded)) + self.assertEqual(exc.args, loaded.args) def test_suite(): From 47c0e1439b46f70d0f073d42b6bebe0bf95a2de3 Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Tue, 8 Nov 2016 21:18:54 +0100 Subject: [PATCH 6/7] Use cPickle for Python 2. --- src/tests/test_exceptions.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tests/test_exceptions.py b/src/tests/test_exceptions.py index 818837bd6..2585de6f0 100644 --- a/src/tests/test_exceptions.py +++ b/src/tests/test_exceptions.py @@ -334,7 +334,10 @@ def testExceptionIsInstanceOfSystemObject(self): def testPicklingExceptions(self): from System import Exception - import pickle + try + import cPickle as pickle + except ImportError: + import pickle exc = Exception("test") dumped = pickle.dumps(exc) From 1af62ea8e417696dd58d3ebf7aae2bdb9d1505a0 Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Tue, 8 Nov 2016 21:25:56 +0100 Subject: [PATCH 7/7] Fix typo. --- src/tests/test_exceptions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/test_exceptions.py b/src/tests/test_exceptions.py index 2585de6f0..892d6f062 100644 --- a/src/tests/test_exceptions.py +++ b/src/tests/test_exceptions.py @@ -334,7 +334,7 @@ def testExceptionIsInstanceOfSystemObject(self): def testPicklingExceptions(self): from System import Exception - try + try: import cPickle as pickle except ImportError: import pickle 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