internal static IntPtr GetInstHandle(object ob, Type type) { ClassBase cc = ClassManager.GetClass(type); CLRObject co = GetInstance(ob, cc.tpHandle); return(co.pyHandle); }
public static void InvokeCtor(IPythonDerivedType obj, string origCtorName, object[] args) { // call the base constructor obj.GetType().InvokeMember(origCtorName, BindingFlags.InvokeMethod, null, obj, args); CLRObject self = null; IntPtr gs = Runtime.PyGILState_Ensure(); try { // create the python object IntPtr type = TypeManager.GetTypeHandle(obj.GetType()); self = new CLRObject(obj, type); // set __pyobj__ to self and deref the python object which will allow this // object to be collected. FieldInfo fi = obj.GetType().GetField("__pyobj__"); fi.SetValue(obj, self); } finally { // Decrement the python object's reference count. // This doesn't actually destroy the object, it just sets the reference to this object // to be a weak reference and it will be destroyed when the C# object is destroyed. if (null != self) { Runtime.XDecref(self.pyHandle); } Runtime.PyGILState_Release(gs); } }
/// <summary> /// SetError Method /// </summary> /// <remarks> /// 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. /// </remarks> public static void SetError(Exception e) { // Because delegates allow arbitrary nesting 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. var pe = e as PythonException; if (pe != null) { Runtime.XIncref(pe.PyType); Runtime.XIncref(pe.PyValue); Runtime.XIncref(pe.PyTB); Runtime.PyErr_Restore(pe.PyType, pe.PyValue, pe.PyTB); return; } IntPtr op = CLRObject.GetInstHandle(e); IntPtr etype = Runtime.PyObject_GetAttrString(op, "__class__"); Runtime.PyErr_SetObject(etype, op); Runtime.XDecref(etype); Runtime.XDecref(op); }
/// <summary> /// 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. /// </summary> /// <param name="ob">The python object wrapping </param> internal static void SetArgsAndCause(IntPtr ob) { // e: A CLR Exception Exception e = ExceptionClassObject.ToException(ob); if (e == null) { return; } IntPtr args; if (!string.IsNullOrEmpty(e.Message)) { 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); #if PYTHON3 if (e.InnerException != null) { IntPtr cause = CLRObject.GetInstHandle(e.InnerException); Marshal.WriteIntPtr(ob, ExceptionOffset.cause, cause); } #endif }
/// <summary> /// Implements __new__ for reflected classes and value types. /// </summary> public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { var self = GetManagedObject(tp) as ClassObject; // Sanity check: this ensures a graceful error if someone does // something intentially wrong like use the managed metatype for // a class that is not really derived from a managed class. if (self == null) { return(Exceptions.RaiseTypeError("invalid object")); } Type type = self.type; // Primitive types do not have constructors, but they look like // they do from Python. If the ClassObject represents one of the // convertible primitive types, just convert the arg directly. if (type.IsPrimitive || type == typeof(string)) { if (Runtime.PyTuple_Size(args) != 1) { Exceptions.SetError(Exceptions.TypeError, "no constructors match given arguments"); return(IntPtr.Zero); } IntPtr op = Runtime.PyTuple_GetItem(args, 0); object result; if (!Converter.ToManaged(op, type, out result, true)) { return(IntPtr.Zero); } return(CLRObject.GetInstHandle(result, tp)); } if (type.IsAbstract) { Exceptions.SetError(Exceptions.TypeError, "cannot instantiate abstract class"); return(IntPtr.Zero); } if (type.IsEnum) { Exceptions.SetError(Exceptions.TypeError, "cannot instantiate enumeration"); return(IntPtr.Zero); } object obj = self.binder.InvokeRaw(IntPtr.Zero, args, kw); if (obj == null) { return(IntPtr.Zero); } return(CLRObject.GetInstHandle(obj, tp)); }
/// <summary> /// FromManagedObject Method /// </summary> /// <remarks> /// Given an arbitrary managed object, return a Python instance that /// reflects the managed object. /// </remarks> public static PyObject FromManagedObject(object ob) { // Special case: if ob is null, we return None. if (ob == null) { Runtime.XIncref(Runtime.PyNone); return(new PyObject(Runtime.PyNone)); } IntPtr op = CLRObject.GetInstHandle(ob); return(new PyObject(op)); }
public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { var self = GetManagedObject(tp) as ArrayObject; if (Runtime.PyTuple_Size(args) != 1) { return(Exceptions.RaiseTypeError("array expects 1 argument")); } IntPtr op = Runtime.PyTuple_GetItem(args, 0); object result; if (!Converter.ToManaged(op, self.type, out result, true)) { return(IntPtr.Zero); } return(CLRObject.GetInstHandle(result, tp)); }
/// <summary> /// DelegateObject __new__ implementation. The result of this is a new /// PyObject whose type is DelegateObject and whose ob_data is a handle /// to an actual delegate instance. The method wrapped by the actual /// delegate instance belongs to an object generated to relay the call /// to the Python callable passed in. /// </summary> public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { var self = (DelegateObject)GetManagedObject(tp); if (Runtime.PyTuple_Size(args) != 1) { return(Exceptions.RaiseTypeError("class takes exactly one argument")); } IntPtr method = Runtime.PyTuple_GetItem(args, 0); if (Runtime.PyCallable_Check(method) != 1) { return(Exceptions.RaiseTypeError("argument must be callable")); } Delegate d = PythonEngine.DelegateManager.GetDelegate(self.type, method); return(CLRObject.GetInstHandle(d, self.pyHandle)); }
/// <summary> /// Implements __new__ for reflected interface types. /// </summary> public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { var self = (InterfaceObject)GetManagedObject(tp); var nargs = Runtime.PyTuple_Size(args); Type type = self.type; object obj; if (nargs == 1) { IntPtr inst = Runtime.PyTuple_GetItem(args, 0); var co = GetManagedObject(inst) as CLRObject; if (co == null || !type.IsInstanceOfType(co.inst)) { Exceptions.SetError(Exceptions.TypeError, $"object does not implement {type.Name}"); return(IntPtr.Zero); } obj = co.inst; } else if (nargs == 0 && self.ctor != null) { obj = self.ctor.Invoke(null); if (obj == null || !type.IsInstanceOfType(obj)) { Exceptions.SetError(Exceptions.TypeError, "CoClass default constructor failed"); return(IntPtr.Zero); } } else { Exceptions.SetError(Exceptions.TypeError, "interface takes exactly one argument"); return(IntPtr.Zero); } return(CLRObject.GetInstHandle(obj, self.pyHandle)); }
/// <summary> /// BoundContructor.__call__(PyObject *callable_object, PyObject *args, PyObject *kw) /// </summary> /// <param name="op"> PyObject *callable_object </param> /// <param name="args"> PyObject *args </param> /// <param name="kw"> PyObject *kw </param> /// <returns> A reference to a new instance of the class by invoking the selected ctor(). </returns> public static IntPtr tp_call(IntPtr op, IntPtr args, IntPtr kw) { var self = (BoundContructor)GetManagedObject(op); // Even though a call with null ctorInfo just produces the old behavior /*if (self.ctorInfo == null) { * string msg = "Usage: Class.Overloads[CLR_or_python_Type, ...]"; * return Exceptions.RaiseTypeError(msg); * }*/ // Bind using ConstructorBinder.Bind and invoke the ctor providing a null instancePtr // which will fire self.ctorInfo using ConstructorInfo.Invoke(). object obj = self.ctorBinder.InvokeRaw(IntPtr.Zero, args, kw, self.ctorInfo); if (obj == null) { // XXX set an error return(IntPtr.Zero); } // Instantiate the python object that wraps the result of the method call // and return the PyObject* to it. return(CLRObject.GetInstHandle(obj, self.pyTypeHndl)); }
internal static IntPtr GetInstHandle(object ob) { CLRObject co = GetInstance(ob); return(co.pyHandle); }
internal static IntPtr ToPython(object value, Type type) { if (value is PyObject) { IntPtr handle = ((PyObject)value).Handle; Runtime.XIncref(handle); return(handle); } IntPtr result = IntPtr.Zero; // Null always converts to None in Python. if (value == null) { result = Runtime.PyNone; Runtime.XIncref(result); return(result); } if (value is IList && !(value is INotifyPropertyChanged) && value.GetType().IsGenericType) { using (var resultlist = new PyList()) { foreach (object o in (IEnumerable)value) { using (var p = new PyObject(ToPython(o, o?.GetType()))) { resultlist.Append(p); } } Runtime.XIncref(resultlist.Handle); return(resultlist.Handle); } } // it the type is a python subclass of a managed type then return the // underlying python object rather than construct a new wrapper object. var pyderived = value as IPythonDerivedType; if (null != pyderived) { #if NETSTANDARD return(ClassDerivedObject.ToPython(pyderived)); #else // if object is remote don't do this if (!System.Runtime.Remoting.RemotingServices.IsTransparentProxy(pyderived)) { return(ClassDerivedObject.ToPython(pyderived)); } #endif } // hmm - from Python, we almost never care what the declared // type is. we'd rather have the object bound to the actual // implementing class. type = value.GetType(); TypeCode tc = Type.GetTypeCode(type); switch (tc) { case TypeCode.Object: return(CLRObject.GetInstHandle(value, type)); case TypeCode.String: return(Runtime.PyUnicode_FromString((string)value)); case TypeCode.Int32: return(Runtime.PyInt_FromInt32((int)value)); case TypeCode.Boolean: if ((bool)value) { Runtime.XIncref(Runtime.PyTrue); return(Runtime.PyTrue); } Runtime.XIncref(Runtime.PyFalse); return(Runtime.PyFalse); case TypeCode.Byte: return(Runtime.PyInt_FromInt32((int)((byte)value))); case TypeCode.Char: return(Runtime.PyUnicode_FromOrdinal((int)((char)value))); case TypeCode.Int16: return(Runtime.PyInt_FromInt32((int)((short)value))); case TypeCode.Int64: return(Runtime.PyLong_FromLongLong((long)value)); case TypeCode.Single: // return Runtime.PyFloat_FromDouble((double)((float)value)); string ss = ((float)value).ToString(nfi); IntPtr ps = Runtime.PyString_FromString(ss); IntPtr op = Runtime.PyFloat_FromString(ps, IntPtr.Zero); Runtime.XDecref(ps); return(op); case TypeCode.Double: return(Runtime.PyFloat_FromDouble((double)value)); case TypeCode.SByte: return(Runtime.PyInt_FromInt32((int)((sbyte)value))); case TypeCode.UInt16: return(Runtime.PyInt_FromInt32((int)((ushort)value))); case TypeCode.UInt32: return(Runtime.PyLong_FromUnsignedLong((uint)value)); case TypeCode.UInt64: return(Runtime.PyLong_FromUnsignedLongLong((ulong)value)); default: if (value is IEnumerable) { using (var resultlist = new PyList()) { foreach (object o in (IEnumerable)value) { using (var p = new PyObject(ToPython(o, o?.GetType()))) { resultlist.Append(p); } } Runtime.XIncref(resultlist.Handle); return(resultlist.Handle); } } result = CLRObject.GetInstHandle(value, type); return(result); } }