diff --git a/src/embed_tests/TestConverter.cs b/src/embed_tests/TestConverter.cs index 40219973b..875adf8ef 100644 --- a/src/embed_tests/TestConverter.cs +++ b/src/embed_tests/TestConverter.cs @@ -1,12 +1,27 @@ using System; using System.Collections.Generic; +using System.Linq; + using NUnit.Framework; + using Python.Runtime; +using PyRuntime = Python.Runtime.Runtime; + namespace Python.EmbeddingTest { public class TestConverter { + static readonly Type[] _numTypes = new Type[] + { + typeof(short), + typeof(ushort), + typeof(int), + typeof(uint), + typeof(long), + typeof(ulong) + }; + [OneTimeSetUp] public void SetUp() { @@ -47,6 +62,60 @@ public void TestConvertDoubleToManaged( Assert.IsTrue(((double) convertedValue).Equals(testValue)); } + [Test] + public void CovertTypeError() + { + Type[] floatTypes = new Type[] + { + typeof(float), + typeof(double) + }; + using (var s = new PyString("abc")) + { + foreach (var type in _numTypes.Union(floatTypes)) + { + object value; + try + { + bool res = Converter.ToManaged(s.Handle, type, out value, true); + Assert.IsFalse(res); + var bo = Exceptions.ExceptionMatches(Exceptions.TypeError); + Assert.IsTrue(Exceptions.ExceptionMatches(Exceptions.TypeError) + || Exceptions.ExceptionMatches(Exceptions.ValueError)); + } + finally + { + Exceptions.Clear(); + } + } + } + } + + [Test] + public void ConvertOverflow() + { + using (var num = new PyLong(ulong.MaxValue)) + { + IntPtr largeNum = PyRuntime.PyNumber_Add(num.Handle, num.Handle); + try + { + object value; + foreach (var type in _numTypes) + { + bool res = Converter.ToManaged(largeNum, type, out value, true); + Assert.IsFalse(res); + Assert.IsTrue(Exceptions.ExceptionMatches(Exceptions.OverflowError)); + Exceptions.Clear(); + } + } + finally + { + Exceptions.Clear(); + PyRuntime.XDecref(largeNum); + } + } + } + [Test] public void RawListProxy() { diff --git a/src/runtime/NewReference.cs b/src/runtime/NewReference.cs index 6e66232d0..89d53bb36 100644 --- a/src/runtime/NewReference.cs +++ b/src/runtime/NewReference.cs @@ -27,14 +27,18 @@ public PyObject MoveToPyObject() this.pointer = IntPtr.Zero; return result; } + /// /// Removes this reference to a Python object, and sets it to null. /// public void Dispose() { - if (!this.IsNull()) - Runtime.XDecref(this.pointer); - this.pointer = IntPtr.Zero; + if (this.IsNull()) + { + return; + } + Runtime.XDecref(pointer); + pointer = IntPtr.Zero; } /// diff --git a/src/runtime/converter.cs b/src/runtime/converter.cs index 734422ed0..58b372fa1 100644 --- a/src/runtime/converter.cs +++ b/src/runtime/converter.cs @@ -1,11 +1,10 @@ using System; using System.Collections; using System.Collections.Generic; +using System.ComponentModel; using System.Globalization; -using System.Reflection; using System.Runtime.InteropServices; using System.Security; -using System.ComponentModel; namespace Python.Runtime { @@ -477,11 +476,9 @@ internal static bool ToManagedValue(IntPtr value, Type obType, /// private static bool ToPrimitive(IntPtr value, Type obType, out object result, bool setError) { - IntPtr overflow = Exceptions.OverflowError; TypeCode tc = Type.GetTypeCode(obType); result = null; - IntPtr op; - int ival; + IntPtr op = IntPtr.Zero; switch (tc) { @@ -495,312 +492,278 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo return true; case TypeCode.Int32: - // Python3 always use PyLong API - op = Runtime.PyNumber_Long(value); - if (op == IntPtr.Zero) { - Exceptions.Clear(); - if (Exceptions.ExceptionMatches(overflow)) + // Python3 always use PyLong API + long num = Runtime.PyLong_AsLongLong(value); + if (num == -1 && Exceptions.ErrorOccurred()) + { + goto convert_error; + } + if (num > Int32.MaxValue || num < Int32.MinValue) { goto overflow; } - goto type_error; - } - long ll = (long)Runtime.PyLong_AsLongLong(op); - Runtime.XDecref(op); - if (ll == -1 && Exceptions.ErrorOccurred()) - { - goto overflow; - } - if (ll > Int32.MaxValue || ll < Int32.MinValue) - { - goto overflow; + result = (int)num; + return true; } - result = (int)ll; - return true; case TypeCode.Boolean: result = Runtime.PyObject_IsTrue(value) != 0; return true; case TypeCode.Byte: - if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { - if (Runtime.PyBytes_Size(value) == 1) + if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { - op = Runtime.PyBytes_AS_STRING(value); - result = (byte)Marshal.ReadByte(op); - return true; + if (Runtime.PyBytes_Size(value) == 1) + { + op = Runtime.PyBytes_AS_STRING(value); + result = (byte)Marshal.ReadByte(op); + return true; + } + goto type_error; } - goto type_error; - } - op = Runtime.PyNumber_Int(value); - if (op == IntPtr.Zero) - { - if (Exceptions.ExceptionMatches(overflow)) + int num = Runtime.PyLong_AsLong(value); + if (num == -1 && Exceptions.ErrorOccurred()) + { + goto convert_error; + } + if (num > Byte.MaxValue || num < Byte.MinValue) { goto overflow; } - goto type_error; + result = (byte)num; + return true; } - ival = (int)Runtime.PyInt_AsLong(op); - Runtime.XDecref(op); - - if (ival > Byte.MaxValue || ival < Byte.MinValue) - { - goto overflow; - } - byte b = (byte)ival; - result = b; - return true; case TypeCode.SByte: - if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { - if (Runtime.PyBytes_Size(value) == 1) + if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { - op = Runtime.PyBytes_AS_STRING(value); - result = (byte)Marshal.ReadByte(op); - return true; + if (Runtime.PyBytes_Size(value) == 1) + { + op = Runtime.PyBytes_AS_STRING(value); + result = (byte)Marshal.ReadByte(op); + return true; + } + goto type_error; } - goto type_error; - } - op = Runtime.PyNumber_Int(value); - if (op == IntPtr.Zero) - { - if (Exceptions.ExceptionMatches(overflow)) + int num = Runtime.PyLong_AsLong(value); + if (num == -1 && Exceptions.ErrorOccurred()) + { + goto convert_error; + } + if (num > SByte.MaxValue || num < SByte.MinValue) { goto overflow; } - goto type_error; - } - ival = (int)Runtime.PyInt_AsLong(op); - Runtime.XDecref(op); - - if (ival > SByte.MaxValue || ival < SByte.MinValue) - { - goto overflow; + result = (sbyte)num; + return true; } - sbyte sb = (sbyte)ival; - result = sb; - return true; case TypeCode.Char: - if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { - if (Runtime.PyBytes_Size(value) == 1) + if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { - op = Runtime.PyBytes_AS_STRING(value); - result = (byte)Marshal.ReadByte(op); - return true; + if (Runtime.PyBytes_Size(value) == 1) + { + op = Runtime.PyBytes_AS_STRING(value); + result = (byte)Marshal.ReadByte(op); + return true; + } + goto type_error; } - goto type_error; - } - else if (Runtime.PyObject_TypeCheck(value, Runtime.PyUnicodeType)) - { - if (Runtime.PyUnicode_GetSize(value) == 1) + else if (Runtime.PyObject_TypeCheck(value, Runtime.PyUnicodeType)) { - op = Runtime.PyUnicode_AsUnicode(value); - Char[] buff = new Char[1]; - Marshal.Copy(op, buff, 0, 1); - result = buff[0]; - return true; + if (Runtime.PyUnicode_GetSize(value) == 1) + { + op = Runtime.PyUnicode_AsUnicode(value); + Char[] buff = new Char[1]; + Marshal.Copy(op, buff, 0, 1); + result = buff[0]; + return true; + } + goto type_error; } - goto type_error; - } - - op = Runtime.PyNumber_Int(value); - if (op == IntPtr.Zero) - { - goto type_error; - } - ival = Runtime.PyInt_AsLong(op); - Runtime.XDecref(op); - if (ival > Char.MaxValue || ival < Char.MinValue) - { - goto overflow; + int num = Runtime.PyLong_AsLong(value); + if (num == -1 && Exceptions.ErrorOccurred()) + { + goto convert_error; + } + if (num > Char.MaxValue || num < Char.MinValue) + { + goto overflow; + } + result = (char)num; + return true; } - result = (char)ival; - return true; case TypeCode.Int16: - op = Runtime.PyNumber_Int(value); - if (op == IntPtr.Zero) { - if (Exceptions.ExceptionMatches(overflow)) + int num = Runtime.PyLong_AsLong(value); + if (num == -1 && Exceptions.ErrorOccurred()) + { + goto convert_error; + } + if (num > Int16.MaxValue || num < Int16.MinValue) { goto overflow; } - goto type_error; - } - ival = (int)Runtime.PyInt_AsLong(op); - Runtime.XDecref(op); - if (ival > Int16.MaxValue || ival < Int16.MinValue) - { - goto overflow; + result = (short)num; + return true; } - short s = (short)ival; - result = s; - return true; case TypeCode.Int64: - op = Runtime.PyNumber_Long(value); - if (op == IntPtr.Zero) { - if (Exceptions.ExceptionMatches(overflow)) + long num = (long)Runtime.PyLong_AsLongLong(value); + if (num == -1 && Exceptions.ErrorOccurred()) { - goto overflow; + goto convert_error; } - goto type_error; - } - long l = (long)Runtime.PyLong_AsLongLong(op); - Runtime.XDecref(op); - if ((l == -1) && Exceptions.ErrorOccurred()) - { - goto overflow; + result = num; + return true; } - result = l; - return true; case TypeCode.UInt16: - op = Runtime.PyNumber_Int(value); - if (op == IntPtr.Zero) { - if (Exceptions.ExceptionMatches(overflow)) + long num = Runtime.PyLong_AsLong(value); + if (num == -1 && Exceptions.ErrorOccurred()) + { + goto convert_error; + } + if (num > UInt16.MaxValue || num < UInt16.MinValue) { goto overflow; } - goto type_error; - } - ival = (int)Runtime.PyInt_AsLong(op); - Runtime.XDecref(op); - if (ival > UInt16.MaxValue || ival < UInt16.MinValue) - { - goto overflow; + result = (ushort)num; + return true; } - ushort us = (ushort)ival; - result = us; - return true; case TypeCode.UInt32: - op = Runtime.PyNumber_Long(value); - if (op == IntPtr.Zero) { - if (Exceptions.ExceptionMatches(overflow)) + op = value; + if (Runtime.PyObject_TYPE(value) != Runtime.PyLongType) { - goto overflow; + op = Runtime.PyNumber_Long(value); + if (op == IntPtr.Zero) + { + goto convert_error; + } } - goto type_error; - } - - uint ui; - try - { - ui = Convert.ToUInt32(Runtime.PyLong_AsUnsignedLong(op)); - } catch (OverflowException) - { - // Probably wasn't an overflow in python but was in C# (e.g. if cpython - // longs are 64 bit then 0xFFFFFFFF + 1 will not overflow in - // PyLong_AsUnsignedLong) - Runtime.XDecref(op); - goto overflow; - } - - - if (Exceptions.ErrorOccurred()) - { - Runtime.XDecref(op); - goto overflow; - } - - IntPtr check = Runtime.PyLong_FromUnsignedLong(ui); - int err = Runtime.PyObject_Compare(check, op); - Runtime.XDecref(check); - Runtime.XDecref(op); - if (0 != err || Exceptions.ErrorOccurred()) - { - goto overflow; + if (Runtime.Is32Bit || Runtime.IsWindows) + { + uint num = Runtime.PyLong_AsUnsignedLong32(op); + if (num == uint.MaxValue && Exceptions.ErrorOccurred()) + { + goto convert_error; + } + result = num; + } + else + { + ulong num = Runtime.PyLong_AsUnsignedLong64(op); + if (num == ulong.MaxValue && Exceptions.ErrorOccurred()) + { + goto convert_error; + } + try + { + result = Convert.ToUInt32(num); + } + catch (OverflowException) + { + // Probably wasn't an overflow in python but was in C# (e.g. if cpython + // longs are 64 bit then 0xFFFFFFFF + 1 will not overflow in + // PyLong_AsUnsignedLong) + goto overflow; + } + } + return true; } - result = ui; - return true; - case TypeCode.UInt64: - op = Runtime.PyNumber_Long(value); - if (op == IntPtr.Zero) { - if (Exceptions.ExceptionMatches(overflow)) + op = value; + if (Runtime.PyObject_TYPE(value) != Runtime.PyLongType) + { + op = Runtime.PyNumber_Long(value); + if (op == IntPtr.Zero) + { + goto convert_error; + } + } + ulong num = Runtime.PyLong_AsUnsignedLongLong(op); + if (num == ulong.MaxValue && Exceptions.ErrorOccurred()) { goto overflow; } - goto type_error; - } - ulong ul = (ulong)Runtime.PyLong_AsUnsignedLongLong(op); - Runtime.XDecref(op); - if (Exceptions.ErrorOccurred()) - { - goto overflow; + result = num; + return true; } - result = ul; - return true; - case TypeCode.Single: - op = Runtime.PyNumber_Float(value); - if (op == IntPtr.Zero) { - if (Exceptions.ExceptionMatches(overflow)) + double num = Runtime.PyFloat_AsDouble(value); + if (num == -1.0 && Exceptions.ErrorOccurred()) { - goto overflow; + goto convert_error; } - goto type_error; - } - double dd = Runtime.PyFloat_AsDouble(op); - Runtime.CheckExceptionOccurred(); - Runtime.XDecref(op); - if (dd > Single.MaxValue || dd < Single.MinValue) - { - if (!double.IsInfinity(dd)) + if (num > Single.MaxValue || num < Single.MinValue) { - goto overflow; + if (!double.IsInfinity(num)) + { + goto overflow; + } } + result = (float)num; + return true; } - result = (float)dd; - return true; case TypeCode.Double: - op = Runtime.PyNumber_Float(value); - if (op == IntPtr.Zero) { - goto type_error; + double num = Runtime.PyFloat_AsDouble(value); + if (num == -1.0 && Exceptions.ErrorOccurred()) + { + goto convert_error; + } + result = num; + return true; } - double d = Runtime.PyFloat_AsDouble(op); - Runtime.CheckExceptionOccurred(); - Runtime.XDecref(op); - result = d; - return true; + default: + goto type_error; } + convert_error: + if (op != value) + { + Runtime.XDecref(op); + } + if (!setError) + { + Exceptions.Clear(); + } + return false; - type_error: - + type_error: if (setError) { string tpName = Runtime.PyObject_GetTypeName(value); Exceptions.SetError(Exceptions.TypeError, $"'{tpName}' value cannot be converted to {obType}"); } - return false; - overflow: - + overflow: + // C# level overflow error + if (op != value) + { + Runtime.XDecref(op); + } if (setError) { Exceptions.SetError(Exceptions.OverflowError, "value too large to convert"); } - return false; } diff --git a/src/runtime/pyansistring.cs b/src/runtime/pyansistring.cs index 3d1d6ab68..185cc6c94 100644 --- a/src/runtime/pyansistring.cs +++ b/src/runtime/pyansistring.cs @@ -45,7 +45,7 @@ public PyAnsiString(PyObject o) public PyAnsiString(string s) { obj = Runtime.PyString_FromString(s); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(obj); } diff --git a/src/runtime/pyfloat.cs b/src/runtime/pyfloat.cs index edfaca542..d6fb55f26 100644 --- a/src/runtime/pyfloat.cs +++ b/src/runtime/pyfloat.cs @@ -51,7 +51,7 @@ public PyFloat(PyObject o) public PyFloat(double value) { obj = Runtime.PyFloat_FromDouble(value); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(obj); } @@ -66,7 +66,7 @@ public PyFloat(string value) using (var s = new PyString(value)) { obj = Runtime.PyFloat_FromString(s.obj, IntPtr.Zero); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(obj); } } @@ -94,7 +94,7 @@ public static bool IsFloatType(PyObject value) public static PyFloat AsFloat(PyObject value) { IntPtr op = Runtime.PyNumber_Float(value.obj); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(op); return new PyFloat(op); } } diff --git a/src/runtime/pyint.cs b/src/runtime/pyint.cs index 217cf7e20..31295c899 100644 --- a/src/runtime/pyint.cs +++ b/src/runtime/pyint.cs @@ -51,7 +51,7 @@ public PyInt(PyObject o) public PyInt(int value) { obj = Runtime.PyInt_FromInt32(value); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(obj); } @@ -65,7 +65,7 @@ public PyInt(int value) public PyInt(uint value) { obj = Runtime.PyInt_FromInt64(value); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(obj); } @@ -78,7 +78,7 @@ public PyInt(uint value) public PyInt(long value) { obj = Runtime.PyInt_FromInt64(value); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(obj); } @@ -92,7 +92,7 @@ public PyInt(long value) public PyInt(ulong value) { obj = Runtime.PyInt_FromInt64((long)value); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(obj); } @@ -151,7 +151,7 @@ public PyInt(sbyte value) : this((int)value) public PyInt(string value) { obj = Runtime.PyInt_FromString(value, IntPtr.Zero, 0); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(obj); } @@ -178,7 +178,7 @@ public static bool IsIntType(PyObject value) public static PyInt AsInt(PyObject value) { IntPtr op = Runtime.PyNumber_Int(value.obj); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(op); return new PyInt(op); } diff --git a/src/runtime/pylong.cs b/src/runtime/pylong.cs index 286af40df..fc101105f 100644 --- a/src/runtime/pylong.cs +++ b/src/runtime/pylong.cs @@ -51,7 +51,7 @@ public PyLong(PyObject o) public PyLong(int value) { obj = Runtime.PyLong_FromLong(value); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(obj); } @@ -65,7 +65,7 @@ public PyLong(int value) public PyLong(uint value) { obj = Runtime.PyLong_FromLong(value); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(obj); } @@ -78,7 +78,7 @@ public PyLong(uint value) public PyLong(long value) { obj = Runtime.PyLong_FromLongLong(value); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(obj); } @@ -92,7 +92,7 @@ public PyLong(long value) public PyLong(ulong value) { obj = Runtime.PyLong_FromUnsignedLongLong(value); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(obj); } @@ -105,7 +105,7 @@ public PyLong(ulong value) public PyLong(short value) { obj = Runtime.PyLong_FromLong(value); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(obj); } @@ -119,7 +119,7 @@ public PyLong(short value) public PyLong(ushort value) { obj = Runtime.PyLong_FromLong(value); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(obj); } @@ -132,7 +132,7 @@ public PyLong(ushort value) public PyLong(byte value) { obj = Runtime.PyLong_FromLong(value); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(obj); } @@ -146,7 +146,7 @@ public PyLong(byte value) public PyLong(sbyte value) { obj = Runtime.PyLong_FromLong(value); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(obj); } @@ -159,7 +159,7 @@ public PyLong(sbyte value) public PyLong(double value) { obj = Runtime.PyLong_FromDouble(value); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(obj); } @@ -172,7 +172,7 @@ public PyLong(double value) public PyLong(string value) { obj = Runtime.PyLong_FromString(value, IntPtr.Zero, 0); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(obj); } @@ -199,7 +199,7 @@ public static bool IsLongType(PyObject value) public static PyLong AsLong(PyObject value) { IntPtr op = Runtime.PyNumber_Long(value.obj); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(op); return new PyLong(op); } diff --git a/src/runtime/pyscope.cs b/src/runtime/pyscope.cs index 8738824f5..9b9c78bae 100644 --- a/src/runtime/pyscope.cs +++ b/src/runtime/pyscope.cs @@ -66,12 +66,13 @@ internal PyScope(IntPtr ptr, PyScopeManager manager) obj = ptr; //Refcount of the variables not increase variables = Runtime.PyModule_GetDict(obj); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(variables); - Runtime.PyDict_SetItemString( + int res = Runtime.PyDict_SetItemString( variables, "__builtins__", Runtime.PyEval_GetBuiltins() ); + PythonException.ThrowIfIsNotZero(res); this.Name = this.Get("__name__"); } @@ -237,7 +238,7 @@ public PyObject Execute(PyObject script, PyDict locals = null) Check(); IntPtr _locals = locals == null ? variables : locals.obj; IntPtr ptr = Runtime.PyEval_EvalCode(script.Handle, variables, _locals); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(ptr); if (ptr == Runtime.PyNone) { Runtime.XDecref(ptr); @@ -282,15 +283,8 @@ public PyObject Eval(string code, PyDict locals = null) NewReference reference = Runtime.PyRun_String( code, flag, variables, _locals ); - try - { - Runtime.CheckExceptionOccurred(); - return reference.MoveToPyObject(); - } - finally - { - reference.Dispose(); - } + PythonException.ThrowIfIsNull(reference); + return reference.MoveToPyObject(); } /// @@ -327,19 +321,8 @@ private void Exec(string code, IntPtr _globals, IntPtr _locals) NewReference reference = Runtime.PyRun_String( code, flag, _globals, _locals ); - - try - { - Runtime.CheckExceptionOccurred(); - if (!reference.IsNone()) - { - throw new PythonException(); - } - } - finally - { - reference.Dispose(); - } + PythonException.ThrowIfIsNull(reference); + reference.Dispose(); } /// diff --git a/src/runtime/pystring.cs b/src/runtime/pystring.cs index c9c4f9f5b..cb18024c5 100644 --- a/src/runtime/pystring.cs +++ b/src/runtime/pystring.cs @@ -54,7 +54,7 @@ public PyString(PyObject o) public PyString(string s) { obj = Runtime.PyUnicode_FromUnicode(s, s.Length); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(obj); } diff --git a/src/runtime/pythonengine.cs b/src/runtime/pythonengine.cs index 4f77bec1d..38ef2ee48 100644 --- a/src/runtime/pythonengine.cs +++ b/src/runtime/pythonengine.cs @@ -465,7 +465,7 @@ public static void EndAllowThreads(IntPtr ts) public static PyObject ImportModule(string name) { IntPtr op = Runtime.PyImport_ImportModule(name); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(op); return new PyObject(op); } @@ -480,7 +480,7 @@ public static PyObject ImportModule(string name) public static PyObject ReloadModule(PyObject module) { IntPtr op = Runtime.PyImport_ReloadModule(module.Handle); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(op); return new PyObject(op); } @@ -495,9 +495,9 @@ public static PyObject ReloadModule(PyObject module) public static PyObject ModuleFromString(string name, string code) { IntPtr c = Runtime.Py_CompileString(code, "none", (int)RunFlagType.File); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(c); IntPtr m = Runtime.PyImport_ExecCodeModule(name, c); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(m); return new PyObject(m); } @@ -505,7 +505,7 @@ public static PyObject Compile(string code, string filename = "", RunFlagType mo { var flag = (int)mode; IntPtr ptr = Runtime.Py_CompileString(code, filename, flag); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(ptr); return new PyObject(ptr); } @@ -587,17 +587,8 @@ internal static PyObject RunString(string code, IntPtr? globals, IntPtr? locals, NewReference result = Runtime.PyRun_String( code, (IntPtr)flag, globals.Value, locals.Value ); - - try - { - Runtime.CheckExceptionOccurred(); - - return result.MoveToPyObject(); - } - finally - { - result.Dispose(); - } + PythonException.ThrowIfIsNull(result); + return result.MoveToPyObject(); } finally { diff --git a/src/runtime/pythonexception.cs b/src/runtime/pythonexception.cs index 8efdccc91..b69ac34e4 100644 --- a/src/runtime/pythonexception.cs +++ b/src/runtime/pythonexception.cs @@ -253,6 +253,14 @@ public static void ThrowIfIsNull(IntPtr ob) } } + internal static void ThrowIfIsNull(BorrowedReference reference) + { + if (reference.IsNull) + { + throw new PythonException(); + } + } + public static void ThrowIfIsNotZero(int value) { if (value != 0) diff --git a/src/runtime/pytuple.cs b/src/runtime/pytuple.cs index 45f3d8350..e534ff5d5 100644 --- a/src/runtime/pytuple.cs +++ b/src/runtime/pytuple.cs @@ -51,7 +51,7 @@ public PyTuple(PyObject o) public PyTuple() { obj = Runtime.PyTuple_New(0); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(obj); } @@ -72,8 +72,8 @@ public PyTuple(PyObject[] items) { IntPtr ptr = items[i].obj; Runtime.XIncref(ptr); - Runtime.PyTuple_SetItem(obj, i, ptr); - Runtime.CheckExceptionOccurred(); + int res = Runtime.PyTuple_SetItem(obj, i, ptr); + PythonException.ThrowIfIsNotZero(res); } } @@ -101,7 +101,7 @@ public static bool IsTupleType(PyObject value) public static PyTuple AsTuple(PyObject value) { IntPtr op = Runtime.PySequence_Tuple(value.obj); - Runtime.CheckExceptionOccurred(); + PythonException.ThrowIfIsNull(op); return new PyTuple(op); } } diff --git a/src/tests/test_conversion.py b/src/tests/test_conversion.py index 74613abd1..313274647 100644 --- a/src/tests/test_conversion.py +++ b/src/tests/test_conversion.py @@ -343,7 +343,7 @@ def test_uint32_conversion(): ob.UInt32Field = System.UInt32(0) assert ob.UInt32Field == 0 - with pytest.raises(TypeError): + with pytest.raises(ValueError): ConversionTest().UInt32Field = "spam" with pytest.raises(TypeError): @@ -382,7 +382,7 @@ def test_uint64_conversion(): ob.UInt64Field = System.UInt64(0) assert ob.UInt64Field == 0 - with pytest.raises(TypeError): + with pytest.raises(ValueError): ConversionTest().UInt64Field = "spam" with pytest.raises(TypeError):