Beispiel #1
0
 /// <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));
 }
Beispiel #2
0
        /// <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)));
        }
Beispiel #3
0
 /// <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)
 {
 }
Beispiel #4
0
 public static void warn(string message, BorrowedReference exception)
 {
     warn(message, exception, 1);
 }
Beispiel #5
0
 internal static bool ToManagedValue(BorrowedReference value, Type obType,
                                     out object result, bool setError)
 => ToManagedValue(value.DangerousGetAddress(), obType, out result, setError);
Beispiel #6
0
        /// <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);
        }
Beispiel #7
0
 /// <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);
 }
Beispiel #8
0
 internal PySequence(BorrowedReference reference) : base(reference)
 {
 }
Beispiel #9
0
        /// <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);
Beispiel #10
0
 /// <summary>
 /// Creates new <see cref="PyList"/> pointing to the same object, as the given reference.
 /// </summary>
 internal PyList(BorrowedReference reference) : base(reference)
 {
 }
Beispiel #11
0
        /// <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);
Beispiel #12
0
        public static void AssertHasReferences(BorrowedReference obj)
        {
            nint refcount = Runtime.Refcount(obj);

            Debug.Assert(refcount > 0, "Object refcount is 0 or less");
        }
Beispiel #13
0
        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));
            }
        }
Beispiel #14
0
        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);
Beispiel #15
0
 internal static void InitGCHandle(BorrowedReference reflectedClrObject, GCHandle handle)
 => InitGCHandle(reflectedClrObject, Runtime.PyObject_TYPE(reflectedClrObject), handle);
Beispiel #16
0
 internal static ManagedType?GetManagedObject(BorrowedReference ob)
 => GetManagedObject(ob.DangerousGetAddress());
Beispiel #17
0
 internal static void SetGCHandle(BorrowedReference reflectedClrObject, GCHandle newHandle)
 => SetGCHandle(reflectedClrObject, Runtime.PyObject_TYPE(reflectedClrObject), newHandle);
Beispiel #18
0
 internal static bool IsInstanceOfManagedType(BorrowedReference ob)
 => IsInstanceOfManagedType(ob.DangerousGetAddressOrNull());
Beispiel #19
0
 /// <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);
 }
Beispiel #20
0
        internal static bool IsManagedType(BorrowedReference type)
        {
            var flags = PyType.GetFlags(type);

            return((flags & TypeFlags.HasClrInstance) != 0);
        }
Beispiel #21
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);
 }
Beispiel #22
0
 internal static GCHandle?TryGetGCHandle(BorrowedReference reflectedClrObject, BorrowedReference type)
 {
     GetGCHandle(reflectedClrObject, type, out IntPtr handle);
     return(handle == IntPtr.Zero ? null : (GCHandle)handle);
 }
Beispiel #23
0
        /// <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);
Beispiel #24
0
        internal static GCHandle?TryGetGCHandle(BorrowedReference reflectedClrObject)
        {
            BorrowedReference reflectedType = Runtime.PyObject_TYPE(reflectedClrObject);

            return(TryGetGCHandle(reflectedClrObject, reflectedType));
        }
Beispiel #25
0
        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);
        }
Beispiel #26
0
 internal static GCHandle GetGCHandle(BorrowedReference reflectedClrObject, BorrowedReference type)
 => TryGetGCHandle(reflectedClrObject, type) ?? throw new InvalidOperationException();
Beispiel #27
0
        /// <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"));
        }
Beispiel #28
0
        internal static void InitGCHandle(BorrowedReference reflectedClrObject, BorrowedReference type, GCHandle handle)
        {
            Debug.Assert(TryGetGCHandle(reflectedClrObject) == null);

            SetGCHandle(reflectedClrObject, type: type, handle);
        }
Beispiel #29
0
        internal static Exception ToException(BorrowedReference ob)
        {
            var co = GetManagedObject(ob) as CLRObject;

            return(co?.inst as Exception);
        }
Beispiel #30
0
 /// <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));
 }