/// <summary> /// Bind the given Python instance and arguments to a particular method /// overload in <see cref="list"/> and return a structure that contains the converted Python /// instance, converted arguments and the correct method to call. /// If unsuccessful, may set a Python error. /// </summary> /// <param name="inst">The Python target of the method invocation.</param> /// <param name="args">The Python arguments.</param> /// <param name="kw">The Python keyword arguments.</param> /// <param name="info">If not null, only bind to that method.</param> /// <returns>A Binding if successful. Otherwise null.</returns> internal Binding?Bind(BorrowedReference inst, BorrowedReference args, BorrowedReference kw, MethodBase?info) { return(Bind(inst, args, kw, info, null)); }
/// <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 NewReference tp_new(BorrowedReference tp, BorrowedReference args, BorrowedReference kw) { var self = (DelegateObject)GetManagedObject(tp) !; if (!self.type.Valid) { return(Exceptions.RaiseTypeError(self.type.DeletedMessage)); } Type type = self.type.Value; if (Runtime.PyTuple_Size(args) != 1) { return(Exceptions.RaiseTypeError("class takes exactly one argument")); } BorrowedReference method = Runtime.PyTuple_GetItem(args, 0); if (Runtime.PyCallable_Check(method) != 1) { return(Exceptions.RaiseTypeError("argument must be callable")); } Delegate d = PythonEngine.DelegateManager.GetDelegate(type, new PyObject(method)); return(CLRObject.GetReference(d, ClassManager.GetClass(type))); }
/// <summary> /// PyTuple Constructor /// </summary> /// <remarks> /// Creates a new PyTuple from an existing object reference. /// The object reference is not checked for type-correctness. /// </remarks> internal PyTuple(BorrowedReference reference) : base(reference) { }
public static void warn(string message, BorrowedReference exception) { warn(message, exception, 1); }
internal static bool ToManagedValue(BorrowedReference value, Type obType, out object result, bool setError) => ToManagedValue(value.DangerousGetAddress(), obType, out result, setError);
/// <summary> /// Creates a new managed type derived from a base type with any virtual /// methods overridden to call out to python if the associated python /// object has overridden the method. /// </summary> internal static Type CreateDerivedType(string name, Type baseType, BorrowedReference dictRef, string namespaceStr, string assemblyName, string moduleName = "Python.Runtime.Dynamic.dll") { // TODO: clean up IntPtr py_dict = dictRef.DangerousGetAddress(); if (null != namespaceStr) { name = namespaceStr + "." + name; } if (null == assemblyName) { assemblyName = "Python.Runtime.Dynamic"; } ModuleBuilder moduleBuilder = GetModuleBuilder(assemblyName, moduleName); Type baseClass = baseType; var interfaces = new List <Type> { typeof(IPythonDerivedType) }; // if the base type is an interface then use System.Object as the base class // and add the base type to the list of interfaces this new class will implement. if (baseType.IsInterface) { interfaces.Add(baseType); baseClass = typeof(object); } TypeBuilder typeBuilder = moduleBuilder.DefineType(name, TypeAttributes.Public | TypeAttributes.Class, baseClass, interfaces.ToArray()); // add a field for storing the python object pointer // FIXME: fb not used FieldBuilder fb = typeBuilder.DefineField("__pyobj__", typeof(CLRObject), FieldAttributes.Public); // override any constructors ConstructorInfo[] constructors = baseClass.GetConstructors(); foreach (ConstructorInfo ctor in constructors) { AddConstructor(ctor, baseType, typeBuilder); } // Override any properties explicitly overridden in python var pyProperties = new HashSet <string>(); if (py_dict != IntPtr.Zero && Runtime.PyDict_Check(py_dict)) { using var dict = new PyDict(new BorrowedReference(py_dict)); using (PyIterable keys = dict.Keys()) { foreach (PyObject pyKey in keys) { using (PyObject value = dict[pyKey]) { if (value.HasAttr("_clr_property_type_")) { string propertyName = pyKey.ToString(); pyProperties.Add(propertyName); // Add the property to the type AddPythonProperty(propertyName, value, typeBuilder); } } } } } // override any virtual methods not already overridden by the properties above MethodInfo[] methods = baseType.GetMethods(); var virtualMethods = new HashSet <string>(); foreach (MethodInfo method in methods) { if (!method.Attributes.HasFlag(MethodAttributes.Virtual) | method.Attributes.HasFlag(MethodAttributes.Final)) { continue; } // skip if this property has already been overridden if ((method.Name.StartsWith("get_") || method.Name.StartsWith("set_")) && pyProperties.Contains(method.Name.Substring(4))) { continue; } // keep track of the virtual methods redirected to the python instance virtualMethods.Add(method.Name); // override the virtual method to call out to the python method, if there is one. AddVirtualMethod(method, baseType, typeBuilder); } // Add any additional methods and properties explicitly exposed from Python. if (py_dict != IntPtr.Zero && Runtime.PyDict_Check(py_dict)) { using var dict = new PyDict(new BorrowedReference(py_dict)); using (PyIterable keys = dict.Keys()) { foreach (PyObject pyKey in keys) { using (PyObject value = dict[pyKey]) { if (value.HasAttr("_clr_return_type_") && value.HasAttr("_clr_arg_types_")) { string methodName = pyKey.ToString(); // if this method has already been redirected to the python method skip it if (virtualMethods.Contains(methodName)) { continue; } // Add the method to the type AddPythonMethod(methodName, value, typeBuilder); } } } } } // add the destructor so the python object created in the constructor gets destroyed MethodBuilder methodBuilder = typeBuilder.DefineMethod("Finalize", MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig, CallingConventions.Standard, typeof(void), Type.EmptyTypes); ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); #pragma warning disable CS0618 // PythonDerivedType is for internal use only il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("Finalize")); #pragma warning restore CS0618 // PythonDerivedType is for internal use only il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, baseClass.GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance)); il.Emit(OpCodes.Ret); Type type = typeBuilder.CreateType(); // scan the assembly so the newly added class can be imported Assembly assembly = Assembly.GetAssembly(type); AssemblyManager.ScanAssembly(assembly); // FIXME: assemblyBuilder not used AssemblyBuilder assemblyBuilder = assemblyBuilders[assemblyName]; return(type); }
/// <summary> /// Sets the current Python exception given a native string. /// This is a wrapper for the Python PyErr_SetString call. /// </summary> public static void SetError(BorrowedReference type, string message) { Runtime.PyErr_SetString(type, message); }
internal PySequence(BorrowedReference reference) : base(reference) { }
/// <summary> /// Descriptor __get__ implementation. This method returns the /// value of the field on the given object. The returned value /// is converted to an appropriately typed Python object. /// </summary> public static NewReference tp_descr_get(BorrowedReference ds, BorrowedReference ob, BorrowedReference tp) { var self = (FieldObject?)GetManagedObject(ds); object result; if (self == null) { Exceptions.SetError(Exceptions.AssertionError, "attempting to access destroyed object"); return(default);
/// <summary> /// Creates new <see cref="PyList"/> pointing to the same object, as the given reference. /// </summary> internal PyList(BorrowedReference reference) : base(reference) { }
/// <summary> /// Descriptor __get__ implementation. This method returns the /// value of the property on the given object. The returned value /// is converted to an appropriately typed Python object. /// </summary> public static NewReference tp_descr_get(BorrowedReference ds, BorrowedReference ob, BorrowedReference tp) { var self = (PropertyObject)GetManagedObject(ds) !; if (!self.info.Valid) { return(Exceptions.RaiseTypeError(self.info.DeletedMessage)); } var info = self.info.Value; MethodInfo?getter = self.getter; object result; if (getter == null) { return(Exceptions.RaiseTypeError("property cannot be read")); } if (ob == null || ob == Runtime.PyNone) { if (!getter.IsStatic) { Exceptions.SetError(Exceptions.TypeError, "instance property must be accessed through a class instance"); return(default);
public static void AssertHasReferences(BorrowedReference obj) { nint refcount = Runtime.Refcount(obj); Debug.Assert(refcount > 0, "Object refcount is 0 or less"); }
internal static IntPtr CreateSubType(IntPtr py_name, IntPtr py_base_type, IntPtr py_dict) { var dictRef = new BorrowedReference(py_dict); // Utility to create a subtype of a managed type with the ability for the // a python subtype able to override the managed implementation string name = Runtime.GetManagedString(py_name); // the derived class can have class attributes __assembly__ and __module__ which // control the name of the assembly and module the new type is created in. object assembly = null; object namespaceStr = null; using (var assemblyKey = new PyString("__assembly__")) { var assemblyPtr = Runtime.PyDict_GetItemWithError(dictRef, assemblyKey.Reference); if (assemblyPtr.IsNull) { if (Exceptions.ErrorOccurred()) { return(IntPtr.Zero); } } else if (!Converter.ToManagedValue(assemblyPtr, typeof(string), out assembly, false)) { return(Exceptions.RaiseTypeError("Couldn't convert __assembly__ value to string")); } using (var namespaceKey = new PyString("__namespace__")) { var pyNamespace = Runtime.PyDict_GetItemWithError(dictRef, namespaceKey.Reference); if (pyNamespace.IsNull) { if (Exceptions.ErrorOccurred()) { return(IntPtr.Zero); } } else if (!Converter.ToManagedValue(pyNamespace, typeof(string), out namespaceStr, false)) { return(Exceptions.RaiseTypeError("Couldn't convert __namespace__ value to string")); } } } // create the new managed type subclassing the base managed type var baseClass = ManagedType.GetManagedObject(py_base_type) as ClassBase; if (null == baseClass) { return(Exceptions.RaiseTypeError("invalid base class, expected CLR class type")); } try { Type subType = ClassDerivedObject.CreateDerivedType(name, baseClass.type, py_dict, (string)namespaceStr, (string)assembly); // create the new ManagedType and python type ClassBase subClass = ClassManager.GetClass(subType); IntPtr py_type = GetTypeHandle(subClass, subType); // by default the class dict will have all the C# methods in it, but as this is a // derived class we want the python overrides in there instead if they exist. IntPtr cls_dict = Marshal.ReadIntPtr(py_type, TypeOffset.tp_dict); ThrowIfIsNotZero(Runtime.PyDict_Update(cls_dict, py_dict)); Runtime.XIncref(py_type); // Update the __classcell__ if it exists var cell = new BorrowedReference(Runtime.PyDict_GetItemString(cls_dict, "__classcell__")); if (!cell.IsNull) { ThrowIfIsNotZero(Runtime.PyCell_Set(cell, py_type)); ThrowIfIsNotZero(Runtime.PyDict_DelItemString(cls_dict, "__classcell__")); } return(py_type); } catch (Exception e) { return(Exceptions.RaiseTypeError(e.Message)); } }
static NewReference CreateMultidimensional(Type elementType, long[] dimensions, BorrowedReference shapeTuple, BorrowedReference pyType) { for (int dimIndex = 0; dimIndex < dimensions.Length; dimIndex++) { BorrowedReference dimObj = Runtime.PyTuple_GetItem(shapeTuple, dimIndex); PythonException.ThrowIfIsNull(dimObj); if (!Runtime.PyInt_Check(dimObj)) { Exceptions.RaiseTypeError("array constructor expects integer dimensions"); return(default);
internal static void InitGCHandle(BorrowedReference reflectedClrObject, GCHandle handle) => InitGCHandle(reflectedClrObject, Runtime.PyObject_TYPE(reflectedClrObject), handle);
internal static ManagedType?GetManagedObject(BorrowedReference ob) => GetManagedObject(ob.DangerousGetAddress());
internal static void SetGCHandle(BorrowedReference reflectedClrObject, GCHandle newHandle) => SetGCHandle(reflectedClrObject, Runtime.PyObject_TYPE(reflectedClrObject), newHandle);
internal static bool IsInstanceOfManagedType(BorrowedReference ob) => IsInstanceOfManagedType(ob.DangerousGetAddressOrNull());
/// <summary> /// ExceptionMatches Method /// </summary> /// <remarks> /// Returns true if the current Python exception matches the given /// Python object. This is a wrapper for PyErr_ExceptionMatches. /// </remarks> public static bool ExceptionMatches(BorrowedReference ob) { return(Runtime.PyErr_ExceptionMatches(ob) != 0); }
internal static bool IsManagedType(BorrowedReference type) { var flags = PyType.GetFlags(type); return((flags & TypeFlags.HasClrInstance) != 0); }
/// <summary> /// SetError Method /// </summary> /// <remarks> /// Sets the current Python exception given a Python object. /// This is a wrapper for the Python PyErr_SetObject call. /// </remarks> public static void SetError(BorrowedReference type, BorrowedReference exceptionObject) { Runtime.PyErr_SetObject(type, exceptionObject); }
internal static GCHandle?TryGetGCHandle(BorrowedReference reflectedClrObject, BorrowedReference type) { GetGCHandle(reflectedClrObject, type, out IntPtr handle); return(handle == IntPtr.Zero ? null : (GCHandle)handle); }
/// <summary> /// Implements __new__ for reflected classes and value types. /// </summary> static NewReference tp_new_impl(BorrowedReference tp, BorrowedReference args, BorrowedReference kw) { // 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 (GetManagedObject(tp) is not ClassObject self) { return(Exceptions.RaiseTypeError("invalid object")); } if (!self.type.Valid) { return(Exceptions.RaiseTypeError(self.type.DeletedMessage)); } Type type = self.type.Value; // 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(default);
internal static GCHandle?TryGetGCHandle(BorrowedReference reflectedClrObject) { BorrowedReference reflectedType = Runtime.PyObject_TYPE(reflectedClrObject); return(TryGetGCHandle(reflectedClrObject, reflectedType)); }
private static void InitClassBase(Type type, ClassBase impl) { // First, we introspect the managed type and build some class // information, including generating the member descriptors // that we'll be putting in the Python class __dict__. ClassInfo info = GetClassInfo(type); impl.indexer = info.indexer; impl.richcompare = new Dictionary <int, MethodObject>(); // Now we allocate the Python type object to reflect the given // managed type, filling the Python type slots with thunks that // point to the managed methods providing the implementation. IntPtr tp = TypeManager.GetTypeHandle(impl, type); // Finally, initialize the class __dict__ and return the object. var dict = new BorrowedReference(Marshal.ReadIntPtr(tp, TypeOffset.tp_dict)); if (impl.dotNetMembers == null) { impl.dotNetMembers = new List <string>(); } IDictionaryEnumerator iter = info.members.GetEnumerator(); while (iter.MoveNext()) { var item = (ManagedType)iter.Value; var name = (string)iter.Key; impl.dotNetMembers.Add(name); Runtime.PyDict_SetItemString(dict, name, item.ObjectReference); // Decref the item now that it's been used. item.DecrRefCount(); if (ClassBase.CilToPyOpMap.TryGetValue(name, out var pyOp)) { impl.richcompare.Add(pyOp, (MethodObject)item); } } // If class has constructors, generate an __doc__ attribute. NewReference doc = default; Type marker = typeof(DocStringAttribute); var attrs = (Attribute[])type.GetCustomAttributes(marker, false); if (attrs.Length != 0) { var attr = (DocStringAttribute)attrs[0]; string docStr = attr.DocString; doc = NewReference.DangerousFromPointer(Runtime.PyString_FromString(docStr)); Runtime.PyDict_SetItem(dict, PyIdentifier.__doc__, doc); } var co = impl as ClassObject; // If this is a ClassObject AND it has constructors, generate a __doc__ attribute. // required that the ClassObject.ctors be changed to internal if (co != null) { if (co.NumCtors > 0) { // Implement Overloads on the class object if (!CLRModule._SuppressOverloads) { var ctors = new ConstructorBinding(type, tp, co.binder); // ExtensionType types are untracked, so don't Incref() them. // TODO: deprecate __overloads__ soon... Runtime.PyDict_SetItem(dict, PyIdentifier.__overloads__, ctors.ObjectReference); Runtime.PyDict_SetItem(dict, PyIdentifier.Overloads, ctors.ObjectReference); ctors.DecrRefCount(); } // don't generate the docstring if one was already set from a DocStringAttribute. if (!CLRModule._SuppressDocs && doc.IsNull()) { doc = co.GetDocString(); Runtime.PyDict_SetItem(dict, PyIdentifier.__doc__, doc); } } } doc.Dispose(); // The type has been modified after PyType_Ready has been called // Refresh the type Runtime.PyType_Modified(tp); }
internal static GCHandle GetGCHandle(BorrowedReference reflectedClrObject, BorrowedReference type) => TryGetGCHandle(reflectedClrObject, type) ?? throw new InvalidOperationException();
/// <summary> /// Implements __call__ for reflected delegate types. /// </summary> public static NewReference tp_call(BorrowedReference ob, BorrowedReference args, BorrowedReference kw) { // TODO: add fast type check! BorrowedReference pytype = Runtime.PyObject_TYPE(ob); var self = (DelegateObject)GetManagedObject(pytype) !; if (GetManagedObject(ob) is CLRObject o && o.inst is Delegate _) { return(self.binder.Invoke(ob, args, kw)); } return(Exceptions.RaiseTypeError("invalid argument")); }
internal static void InitGCHandle(BorrowedReference reflectedClrObject, BorrowedReference type, GCHandle handle) { Debug.Assert(TryGetGCHandle(reflectedClrObject) == null); SetGCHandle(reflectedClrObject, type: type, handle); }
internal static Exception ToException(BorrowedReference ob) { var co = GetManagedObject(ob) as CLRObject; return(co?.inst as Exception); }
/// <summary> /// Bind the given Python instance and arguments to a particular method /// overload in <see cref="list"/> and return a structure that contains the converted Python /// instance, converted arguments and the correct method to call. /// If unsuccessful, may set a Python error. /// </summary> /// <param name="inst">The Python target of the method invocation.</param> /// <param name="args">The Python arguments.</param> /// <param name="kw">The Python keyword arguments.</param> /// <returns>A Binding if successful. Otherwise null.</returns> internal Binding?Bind(BorrowedReference inst, BorrowedReference args, BorrowedReference kw) { return(Bind(inst, args, kw, null, null)); }