/// <summary> /// Remove the given Python object event handler. /// </summary> internal bool RemoveEventHandler(IntPtr target, IntPtr handler) { object obj = null; if (target != IntPtr.Zero) { var co = (CLRObject)GetManagedObject(target); obj = co.inst; } IntPtr hash = Runtime.PyObject_Hash(handler); if (Exceptions.ErrorOccurred() || reg == null) { Exceptions.SetError(Exceptions.ValueError, "unknown event handler"); return(false); } object key = obj ?? info.ReflectedType; var list = reg[key] as ArrayList; if (list == null) { Exceptions.SetError(Exceptions.ValueError, "unknown event handler"); return(false); } object[] args = { null }; MethodInfo mi = info.GetRemoveMethod(true); for (var i = 0; i < list.Count; i++) { var item = (Handler)list[i]; if (item.hash != hash) { continue; } args[0] = item.del; try { mi.Invoke(obj, BindingFlags.Default, null, args, null); } catch { continue; } list.RemoveAt(i); return(true); } Exceptions.SetError(Exceptions.ValueError, "unknown event handler"); return(false); }
/// <summary> /// Equals Method /// </summary> /// <remarks> /// Return true if this object is equal to the given object. This /// method is based on Python equality semantics. /// </remarks> public override bool Equals(object o) { if (!(o is PyObject)) { return(false); } if (obj == ((PyObject)o).obj) { return(true); } int r = Runtime.PyObject_Compare(obj, ((PyObject)o).obj); if (Exceptions.ErrorOccurred()) { throw new PythonException(); } return(r == 0); }
/// <summary> /// Implements __setitem__ for reflected classes and value types. /// </summary> public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) { //ManagedType self = GetManagedObject(ob); IntPtr tp = Runtime.PyObject_TYPE(ob); var cls = (ClassBase)GetManagedObject(tp); if (cls.indexer == null || !cls.indexer.CanSet) { Exceptions.SetError(Exceptions.TypeError, "object doesn't support item assignment"); return(-1); } // Arg may be a tuple in the case of an indexer with multiple // parameters. If so, use it directly, else make a new tuple // with the index arg (method binders expect arg tuples). IntPtr args = idx; var free = false; if (!Runtime.PyTuple_Check(idx)) { args = Runtime.PyTuple_New(1); Runtime.XIncref(idx); Runtime.PyTuple_SetItem(args, 0, idx); free = true; } // Get the args passed in. var i = Runtime.PyTuple_Size(args); IntPtr defaultArgs = cls.indexer.GetDefaultArgs(args); var numOfDefaultArgs = Runtime.PyTuple_Size(defaultArgs); var temp = i + numOfDefaultArgs; IntPtr real = Runtime.PyTuple_New(temp + 1); for (var n = 0; n < i; n++) { IntPtr item = Runtime.PyTuple_GetItem(args, n); Runtime.XIncref(item); Runtime.PyTuple_SetItem(real, n, item); } // Add Default Args if needed for (var n = 0; n < numOfDefaultArgs; n++) { IntPtr item = Runtime.PyTuple_GetItem(defaultArgs, n); Runtime.XIncref(item); Runtime.PyTuple_SetItem(real, n + i, item); } // no longer need defaultArgs Runtime.XDecref(defaultArgs); i = temp; // Add value to argument list Runtime.XIncref(v); Runtime.PyTuple_SetItem(real, i, v); try { cls.indexer.SetItem(ob, real); } finally { Runtime.XDecref(real); if (free) { Runtime.XDecref(args); } } if (Exceptions.ErrorOccurred()) { return(-1); } return(0); }
/// <summary> /// Implements __getitem__ for array types. /// </summary> public static IntPtr mp_subscript(IntPtr ob, IntPtr idx) { var obj = (CLRObject)GetManagedObject(ob); var items = obj.inst as Array; Type itemType = obj.inst.GetType().GetElementType(); int rank = items.Rank; int index; object value; // Note that CLR 1.0 only supports int indexes - methods to // support long indices were introduced in 1.1. We could // support long indices automatically, but given that long // indices are not backward compatible and a relative edge // case, we won't bother for now. // Single-dimensional arrays are the most common case and are // cheaper to deal with than multi-dimensional, so check first. if (rank == 1) { index = Runtime.PyInt_AsLong(idx); if (Exceptions.ErrorOccurred()) { return(Exceptions.RaiseTypeError("invalid index value")); } if (index < 0) { index = items.Length + index; } try { value = items.GetValue(index); } catch (IndexOutOfRangeException) { Exceptions.SetError(Exceptions.IndexError, "array index out of range"); return(IntPtr.Zero); } return(Converter.ToPython(value, itemType)); } // Multi-dimensional arrays can be indexed a la: list[1, 2, 3]. if (!Runtime.PyTuple_Check(idx)) { Exceptions.SetError(Exceptions.TypeError, "invalid index value"); return(IntPtr.Zero); } var count = Runtime.PyTuple_Size(idx); var args = new int[count]; for (var i = 0; i < count; i++) { IntPtr op = Runtime.PyTuple_GetItem(idx, i); index = Runtime.PyInt_AsLong(op); if (Exceptions.ErrorOccurred()) { return(Exceptions.RaiseTypeError("invalid index value")); } if (index < 0) { index = items.GetLength(i) + index; } args.SetValue(index, i); } try { value = items.GetValue(args); } catch (IndexOutOfRangeException) { Exceptions.SetError(Exceptions.IndexError, "array index out of range"); return(IntPtr.Zero); } return(Converter.ToPython(value, itemType)); }
/// <summary> /// Implements __setitem__ for array types. /// </summary> public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) { var obj = (CLRObject)GetManagedObject(ob); var items = obj.inst as Array; Type itemType = obj.inst.GetType().GetElementType(); int rank = items.Rank; int index; object value; if (items.IsReadOnly) { Exceptions.RaiseTypeError("array is read-only"); return(-1); } if (!Converter.ToManaged(v, itemType, out value, true)) { return(-1); } if (rank == 1) { index = Runtime.PyInt_AsLong(idx); if (Exceptions.ErrorOccurred()) { Exceptions.RaiseTypeError("invalid index value"); return(-1); } if (index < 0) { index = items.Length + index; } try { items.SetValue(value, index); } catch (IndexOutOfRangeException) { Exceptions.SetError(Exceptions.IndexError, "array index out of range"); return(-1); } return(0); } if (!Runtime.PyTuple_Check(idx)) { Exceptions.RaiseTypeError("invalid index value"); return(-1); } var count = Runtime.PyTuple_Size(idx); var args = new int[count]; for (var i = 0; i < count; i++) { IntPtr op = Runtime.PyTuple_GetItem(idx, i); index = Runtime.PyInt_AsLong(op); if (Exceptions.ErrorOccurred()) { Exceptions.RaiseTypeError("invalid index value"); return(-1); } if (index < 0) { index = items.GetLength(i) + index; } args.SetValue(index, i); } try { items.SetValue(value, args); } catch (IndexOutOfRangeException) { Exceptions.SetError(Exceptions.IndexError, "array index out of range"); return(-1); } return(0); }
/// <summary> /// Convert a Python value to an instance of a primitive managed type. /// </summary> 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; switch (tc) { case TypeCode.String: string st = Runtime.GetManagedString(value); if (st == null) { goto type_error; } result = st; return(true); case TypeCode.Int32: // Trickery to support 64-bit platforms. if (Runtime.IsPython2 && Runtime.Is32Bit) { op = Runtime.PyNumber_Int(value); // As of Python 2.3, large ints magically convert :( if (Runtime.PyLong_Check(op)) { Runtime.XDecref(op); goto overflow; } if (op == IntPtr.Zero) { if (Exceptions.ExceptionMatches(overflow)) { goto overflow; } goto type_error; } ival = (int)Runtime.PyInt_AsLong(op); Runtime.XDecref(op); result = ival; return(true); } else // Python3 always use PyLong API { op = Runtime.PyNumber_Long(value); if (op == IntPtr.Zero) { Exceptions.Clear(); if (Exceptions.ExceptionMatches(overflow)) { 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)ll; return(true); } case TypeCode.Boolean: result = Runtime.PyObject_IsTrue(value) != 0; return(true); case TypeCode.Byte: #if PYTHON3 if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { if (Runtime.PyBytes_Size(value) == 1) { op = Runtime.PyBytes_AS_STRING(value); result = (byte)Marshal.ReadByte(op); return(true); } goto type_error; } #elif PYTHON2 if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) { if (Runtime.PyString_Size(value) == 1) { op = Runtime.PyString_AsString(value); result = (byte)Marshal.ReadByte(op); return(true); } goto type_error; } #endif op = Runtime.PyNumber_Int(value); if (op == IntPtr.Zero) { if (Exceptions.ExceptionMatches(overflow)) { goto overflow; } goto type_error; } 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 PYTHON3 if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { if (Runtime.PyBytes_Size(value) == 1) { op = Runtime.PyBytes_AS_STRING(value); result = (byte)Marshal.ReadByte(op); return(true); } goto type_error; } #elif PYTHON2 if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) { if (Runtime.PyString_Size(value) == 1) { op = Runtime.PyString_AsString(value); result = (sbyte)Marshal.ReadByte(op); return(true); } goto type_error; } #endif op = Runtime.PyNumber_Int(value); if (op == IntPtr.Zero) { if (Exceptions.ExceptionMatches(overflow)) { goto overflow; } goto type_error; } ival = (int)Runtime.PyInt_AsLong(op); Runtime.XDecref(op); if (ival > SByte.MaxValue || ival < SByte.MinValue) { goto overflow; } sbyte sb = (sbyte)ival; result = sb; return(true); case TypeCode.Char: #if PYTHON3 if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { if (Runtime.PyBytes_Size(value) == 1) { op = Runtime.PyBytes_AS_STRING(value); result = (byte)Marshal.ReadByte(op); return(true); } goto type_error; } #elif PYTHON2 if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) { if (Runtime.PyString_Size(value) == 1) { op = Runtime.PyString_AsString(value); result = (char)Marshal.ReadByte(op); return(true); } goto type_error; } #endif else if (Runtime.PyObject_TypeCheck(value, Runtime.PyUnicodeType)) { 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; } 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; } result = (char)ival; return(true); case TypeCode.Int16: op = Runtime.PyNumber_Int(value); if (op == IntPtr.Zero) { if (Exceptions.ExceptionMatches(overflow)) { goto overflow; } goto type_error; } ival = (int)Runtime.PyInt_AsLong(op); Runtime.XDecref(op); if (ival > Int16.MaxValue || ival < Int16.MinValue) { goto overflow; } short s = (short)ival; result = s; return(true); case TypeCode.Int64: op = Runtime.PyNumber_Long(value); if (op == IntPtr.Zero) { if (Exceptions.ExceptionMatches(overflow)) { goto overflow; } goto type_error; } long l = (long)Runtime.PyLong_AsLongLong(op); Runtime.XDecref(op); if ((l == -1) && Exceptions.ErrorOccurred()) { goto overflow; } result = l; return(true); case TypeCode.UInt16: op = Runtime.PyNumber_Int(value); if (op == IntPtr.Zero) { if (Exceptions.ExceptionMatches(overflow)) { goto overflow; } goto type_error; } ival = (int)Runtime.PyInt_AsLong(op); Runtime.XDecref(op); if (ival > UInt16.MaxValue || ival < UInt16.MinValue) { goto overflow; } ushort us = (ushort)ival; result = us; return(true); case TypeCode.UInt32: op = Runtime.PyNumber_Long(value); if (op == IntPtr.Zero) { if (Exceptions.ExceptionMatches(overflow)) { goto overflow; } goto type_error; } uint ui = (uint)Runtime.PyLong_AsUnsignedLong(op); 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; } result = ui; return(true); case TypeCode.UInt64: op = Runtime.PyNumber_Long(value); if (op == IntPtr.Zero) { if (Exceptions.ExceptionMatches(overflow)) { goto overflow; } goto type_error; } ulong ul = (ulong)Runtime.PyLong_AsUnsignedLongLong(op); Runtime.XDecref(op); if (Exceptions.ErrorOccurred()) { goto overflow; } result = ul; return(true); case TypeCode.Single: op = Runtime.PyNumber_Float(value); if (op == IntPtr.Zero) { if (Exceptions.ExceptionMatches(overflow)) { goto overflow; } 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)) { goto overflow; } } result = (float)dd; return(true); case TypeCode.Double: op = Runtime.PyNumber_Float(value); if (op == IntPtr.Zero) { goto type_error; } double d = Runtime.PyFloat_AsDouble(op); Runtime.CheckExceptionOccurred(); Runtime.XDecref(op); result = d; return(true); } type_error: if (setError) { string tpName = Runtime.PyObject_GetTypeName(value); Exceptions.SetError(Exceptions.TypeError, $"'{tpName}' value cannot be converted to {obType}"); } return(false); overflow: if (setError) { Exceptions.SetError(Exceptions.OverflowError, "value too large to convert"); } return(false); }