Base class for Python types that reflect managed types / classes. Concrete subclasses include ClassObject and DelegateObject. This class provides common attributes and common machinery for doing class initialization (initialization of the class __dict__). The concrete subclasses provide slot implementations appropriate for each variety of reflected type.
Наследование: ManagedType
Пример #1
0
        static IntPtr DoInstanceCheck(IntPtr tp, IntPtr args, bool checkType)
        {
            ClassBase cb = GetManagedObject(tp) as ClassBase;

            if (cb == null)
            {
                return(Runtime.PyFalse);
            }

            using (PyList argsObj = new PyList(args))
            {
                if (argsObj.Length() != 1)
                {
                    return(Exceptions.RaiseTypeError("Invalid parameter count"));
                }

                PyObject arg = argsObj[0];
                PyObject otherType;
                if (checkType)
                {
                    otherType = arg;
                }
                else
                {
                    otherType = arg.GetPythonType();
                }

                if (Runtime.PyObject_TYPE(otherType.Handle) != PyCLRMetaType)
                {
                    return(Runtime.PyFalse);
                }

                ClassBase otherCb = GetManagedObject(otherType.Handle) as ClassBase;
                if (otherCb == null)
                {
                    return(Runtime.PyFalse);
                }

                return(Converter.ToPython(cb.type.IsAssignableFrom(otherCb.type)));
            }
        }
Пример #2
0
        /// <summary>
        /// Return the ClassBase-derived instance that implements a particular
        /// reflected managed type, creating it if it doesn't yet exist.
        /// </summary>
        /// <returns>A Borrowed reference to the ClassBase object</returns>
        internal static ClassBase GetClass(Type type)
        {
            ClassBase cb = null;

            cache.TryGetValue(type, out cb);
            if (cb != null)
            {
                return(cb);
            }
            cb = CreateClass(type);
            cache.Add(type, cb);
            // Ensure, that matching Python type exists first.
            // It is required for self-referential classes
            // (e.g. with members, that refer to the same class)
            var pyType = InitPyType(type, cb);

            // Initialize the object later, as this might call this GetClass method
            // recursively (for example when a nested class inherits its declaring class...)
            InitClassBase(type, cb, pyType);
            return(cb);
        }
Пример #3
0
        /// <summary>
        /// Return the ClassBase-derived instance that implements a particular
        /// reflected managed type, creating it if it doesn't yet exist.
        /// </summary>
        internal static ClassBase GetClass(Type type)
        {
            ClassBase cb = null;

            cache.TryGetValue(type, out cb);
            if (cb != null)
            {
                return(cb);
            }
            cb = CreateClass(type);

            // Don't cache Dynamic Types in order to create new types for each instance - Arturo Rodriguez
            if (type != typeof(QuantApp.Kernel.JVM.JVMObject) && type != typeof(System.Dynamic.DynamicMetaObject))
            {
                cache.Add(type, cb);
            }

            // Initialize the object later, as this might call this GetClass method
            // recursively (for example when a nested class inherits its declaring class...)
            InitClassBase(type, cb);
            return(cb);
        }
Пример #4
0
        //===================================================================
        // Preloads all currently-known names for the module namespace. This
        // can be called multiple times, to add names from assemblies that
        // may have been loaded since the last call to the method.
        //===================================================================

        public void LoadNames()
        {
            foreach (string name in AssemblyManager.GetNames(_namespace))
            {
                if (!this.cache.ContainsKey(name))
                {
                    ManagedType attr = this.GetAttribute(name);
                    if (Runtime.wrap_exceptions)
                    {
                        if (attr is ClassBase)
                        {
                            ClassBase c = attr as ClassBase;
                            if (c.is_exception)
                            {
                                IntPtr p = attr.pyHandle;
                                IntPtr r = Exceptions.GetExceptionClassWrapper(p);
                                Runtime.PyDict_SetItemString(dict, name, r);
                                Runtime.Incref(r);
                            }
                        }
                    }
                }
            }
        }
Пример #5
0
        internal static IntPtr CreateType(ManagedType impl, Type clrType)
        {
            // Cleanup the type name to get rid of funny nested type names.
            string name = "CLR." + clrType.FullName;
            int    i    = name.LastIndexOf('+');

            if (i > -1)
            {
                name = name.Substring(i + 1);
            }
            i = name.LastIndexOf('.');
            if (i > -1)
            {
                name = name.Substring(i + 1);
            }

            IntPtr base_         = IntPtr.Zero;
            int    ob_size       = ObjectOffset.Size(Runtime.PyTypeType);
            int    tp_dictoffset = ObjectOffset.DictOffset(Runtime.PyTypeType);

            // XXX Hack, use a different base class for System.Exception
            // Python 2.5+ allows new style class exceptions but they *must*
            // subclass BaseException (or better Exception).
            if (typeof(Exception).IsAssignableFrom(clrType))
            {
                ob_size       = ObjectOffset.Size(Exceptions.Exception);
                tp_dictoffset = ObjectOffset.DictOffset(Exceptions.Exception);
            }

            if (clrType == typeof(Exception))
            {
                base_ = Exceptions.Exception;
            }
            else if (clrType.BaseType != null)
            {
                ClassBase bc = ClassManager.GetClass(clrType.BaseType);
                base_ = bc.pyHandle;
            }

            IntPtr type = AllocateTypeObject(name);

            Marshal.WriteIntPtr(type, TypeOffset.ob_type, Runtime.PyCLRMetaType);
            Runtime.XIncref(Runtime.PyCLRMetaType);

            Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)ob_size);
            Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero);
            Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, (IntPtr)tp_dictoffset);

            InitializeSlots(type, impl.GetType());

            if (base_ != IntPtr.Zero)
            {
                Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_);
                Runtime.XIncref(base_);
            }

            int flags = TypeFlags.Default;

            flags |= TypeFlags.Managed;
            flags |= TypeFlags.HeapType;
            flags |= TypeFlags.BaseType;
            flags |= TypeFlags.HaveGC;
            Util.WriteCLong(type, TypeOffset.tp_flags, flags);

            // Leverage followup initialization from the Python runtime. Note
            // that the type of the new type must PyType_Type at the time we
            // call this, else PyType_Ready will skip some slot initialization.

            Runtime.PyType_Ready(type);

            IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict);
            string mn   = clrType.Namespace ?? "";
            IntPtr mod  = Runtime.PyString_FromString(mn);

            Runtime.PyDict_SetItemString(dict, "__module__", mod);

            // Hide the gchandle of the implementation in a magic type slot.
            GCHandle gc = GCHandle.Alloc(impl);

            Marshal.WriteIntPtr(type, TypeOffset.magic(), (IntPtr)gc);

            // Set the handle attributes on the implementing instance.
            impl.tpHandle = Runtime.PyCLRMetaType;
            impl.gcHandle = gc;
            impl.pyHandle = type;

            //DebugUtil.DumpType(type);

            return(type);
        }
Пример #6
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);
        }
Пример #7
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;

            // 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);
            impl.tpHandle = tp;

            // Finally, initialize the class __dict__ and return the object.
            IntPtr dict = Marshal.ReadIntPtr(tp, TypeOffset.tp_dict);

            IDictionaryEnumerator iter = info.members.GetEnumerator();
            while (iter.MoveNext())
            {
                ManagedType item = (ManagedType)iter.Value;
                string name = (string)iter.Key;
                Runtime.PyDict_SetItemString(dict, name, item.pyHandle);
            }

            // If class has constructors, generate an __doc__ attribute.

            IntPtr doc = IntPtr.Zero;
            Type marker = typeof(DocStringAttribute);
            Attribute[] attrs = (Attribute[])type.GetCustomAttributes(marker, false);
            if (attrs.Length == 0)
            {
                doc = IntPtr.Zero;
            }
            else
            {
                DocStringAttribute attr = (DocStringAttribute)attrs[0];
                string docStr = attr.DocString;
                doc = Runtime.PyString_FromString(docStr);
                Runtime.PyDict_SetItemString(dict, "__doc__", doc);
                Runtime.XDecref(doc);
            }

            ClassObject 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.ctors.Length > 0)
                {
                    // Implement Overloads on the class object
                    if (!CLRModule._SuppressOverloads)
                    {
                        ConstructorBinding ctors = new ConstructorBinding(type, tp, co.binder);
                        // ExtensionType types are untracked, so don't Incref() them.
                        // XXX deprecate __overloads__ soon...
                        Runtime.PyDict_SetItemString(dict, "__overloads__", ctors.pyHandle);
                        Runtime.PyDict_SetItemString(dict, "Overloads", ctors.pyHandle);
                    }

                    // don't generate the docstring if one was already set from a DocStringAttribute.
                    if (!CLRModule._SuppressDocs && doc == IntPtr.Zero)
                    {
                        doc = co.GetDocString();
                        Runtime.PyDict_SetItemString(dict, "__doc__", doc);
                        Runtime.XDecref(doc);
                    }
                }
            }
        }
Пример #8
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, true))
                {
                    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, true))
                    {
                        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.Value,
                                                                    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.
                var cls_dict = new BorrowedReference(Marshal.ReadIntPtr(py_type, TypeOffset.tp_dict));
                ThrowIfIsNotZero(Runtime.PyDict_Update(cls_dict, new BorrowedReference(py_dict)));
                Runtime.XIncref(py_type);
                // Update the __classcell__ if it exists
                BorrowedReference cell = 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));
            }
        }
Пример #9
0
        internal static IntPtr CreateType(ManagedType impl, Type clrType)
        {
            // Cleanup the type name to get rid of funny nested type names.
            string name = $"clr.{clrType.FullName}";
            int    i    = name.LastIndexOf('+');

            if (i > -1)
            {
                name = name.Substring(i + 1);
            }
            i = name.LastIndexOf('.');
            if (i > -1)
            {
                name = name.Substring(i + 1);
            }

            IntPtr base_   = IntPtr.Zero;
            int    ob_size = ObjectOffset.Size(Runtime.PyTypeType);

            // XXX Hack, use a different base class for System.Exception
            // Python 2.5+ allows new style class exceptions but they *must*
            // subclass BaseException (or better Exception).
            if (typeof(Exception).IsAssignableFrom(clrType))
            {
                ob_size = ObjectOffset.Size(Exceptions.Exception);
            }

            int tp_dictoffset = ob_size + ManagedDataOffsets.ob_dict;

            if (clrType == typeof(Exception))
            {
                base_ = Exceptions.Exception;
            }
            else if (clrType.BaseType != null)
            {
                ClassBase bc = ClassManager.GetClass(clrType.BaseType);
                base_ = bc.pyHandle;
            }

            IntPtr type = AllocateTypeObject(name, Runtime.PyCLRMetaType);

            Marshal.WriteIntPtr(type, TypeOffset.ob_type, Runtime.PyCLRMetaType);
            Runtime.XIncref(Runtime.PyCLRMetaType);

            Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)ob_size);
            Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero);
            Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, (IntPtr)tp_dictoffset);

            // we want to do this after the slot stuff above in case the class itself implements a slot method
            SlotsHolder slotsHolder = CreateSolotsHolder(type);

            InitializeSlots(type, impl.GetType(), slotsHolder);

            if (Marshal.ReadIntPtr(type, TypeOffset.mp_length) == IntPtr.Zero &&
                mp_length_slot.CanAssign(clrType))
            {
                InitializeSlot(type, TypeOffset.mp_length, mp_length_slot.Method, slotsHolder);
            }

            if (!typeof(IEnumerable).IsAssignableFrom(clrType) &&
                !typeof(IEnumerator).IsAssignableFrom(clrType))
            {
                // The tp_iter slot should only be set for enumerable types.
                Marshal.WriteIntPtr(type, TypeOffset.tp_iter, IntPtr.Zero);
            }


            // Only set mp_subscript and mp_ass_subscript for types with indexers
            if (impl is ClassBase cb)
            {
                if (!(impl is ArrayObject))
                {
                    if (cb.indexer == null || !cb.indexer.CanGet)
                    {
                        Marshal.WriteIntPtr(type, TypeOffset.mp_subscript, IntPtr.Zero);
                    }
                    if (cb.indexer == null || !cb.indexer.CanSet)
                    {
                        Marshal.WriteIntPtr(type, TypeOffset.mp_ass_subscript, IntPtr.Zero);
                    }
                }
            }
            else
            {
                Marshal.WriteIntPtr(type, TypeOffset.mp_subscript, IntPtr.Zero);
                Marshal.WriteIntPtr(type, TypeOffset.mp_ass_subscript, IntPtr.Zero);
            }

            if (base_ != IntPtr.Zero)
            {
                Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_);
                Runtime.XIncref(base_);
            }

            const TypeFlags flags = TypeFlags.Default
                                    | TypeFlags.Managed
                                    | TypeFlags.HeapType
                                    | TypeFlags.BaseType
                                    | TypeFlags.HaveGC;

            Util.WriteCLong(type, TypeOffset.tp_flags, (int)flags);

            OperatorMethod.FixupSlots(type, clrType);
            // Leverage followup initialization from the Python runtime. Note
            // that the type of the new type must PyType_Type at the time we
            // call this, else PyType_Ready will skip some slot initialization.

            if (Runtime.PyType_Ready(type) != 0)
            {
                throw new PythonException();
            }

            var    dict = new BorrowedReference(Marshal.ReadIntPtr(type, TypeOffset.tp_dict));
            string mn   = clrType.Namespace ?? "";
            var    mod  = NewReference.DangerousFromPointer(Runtime.PyString_FromString(mn));

            Runtime.PyDict_SetItem(dict, PyIdentifier.__module__, mod);
            mod.Dispose();

            // Hide the gchandle of the implementation in a magic type slot.
            GCHandle gc = impl.AllocGCHandle();

            Marshal.WriteIntPtr(type, TypeOffset.magic(), (IntPtr)gc);

            // Set the handle attributes on the implementing instance.
            impl.tpHandle = type;
            impl.pyHandle = type;

            //DebugUtil.DumpType(type);

            return(type);
        }
Пример #10
0
        //====================================================================
        // Implements __setitem__ for reflected classes and value types.
        //====================================================================

        public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v)
        {
            //ManagedType self = GetManagedObject(ob);
            IntPtr    tp  = Runtime.PyObject_TYPE(ob);
            ClassBase 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;
            bool   free = false;

            if (!Runtime.PyTuple_Check(idx))
            {
                args = Runtime.PyTuple_New(1);
                Runtime.Incref(idx);
                Runtime.PyTuple_SetItem(args, 0, idx);
                free = true;
            }

            // Get the args passed in.
            int    i                = Runtime.PyTuple_Size(args);
            IntPtr defaultArgs      = cls.indexer.GetDefaultArgs(args);
            int    numOfDefaultArgs = Runtime.PyTuple_Size(defaultArgs);
            int    temp             = i + numOfDefaultArgs;
            IntPtr real             = Runtime.PyTuple_New(temp + 1);

            for (int n = 0; n < i; n++)
            {
                IntPtr item = Runtime.PyTuple_GetItem(args, n);
                Runtime.Incref(item);
                Runtime.PyTuple_SetItem(real, n, item);
            }

            // Add Default Args if needed
            for (int n = 0; n < numOfDefaultArgs; n++)
            {
                IntPtr item = Runtime.PyTuple_GetItem(defaultArgs, n);
                Runtime.Incref(item);
                Runtime.PyTuple_SetItem(real, n + i, item);
            }
            // no longer need defaultArgs
            Runtime.Decref(defaultArgs);
            i = temp;

            // Add value to argument list
            Runtime.Incref(v);
            Runtime.PyTuple_SetItem(real, i, v);

            try {
                cls.indexer.SetItem(ob, real);
            }
            finally {
                Runtime.Decref(real);

                if (free)
                {
                    Runtime.Decref(args);
                }
            }

            if (Exceptions.ErrorOccurred())
            {
                return(-1);
            }

            return(0);
        }
Пример #11
0
        internal static MethodInfo MatchByTypeSig(MethodInfo[] msig,
                                                  IntPtr psig)
        {
            IntPtr args = psig;
            bool   free = false;

            if (!Runtime.PyTuple_Check(psig))
            {
                args = Runtime.PyTuple_New(1);
                Runtime.Incref(psig);
                Runtime.PyTuple_SetItem(args, 0, psig);
                free = true;
            }

            int        plen  = Runtime.PyTuple_Size(args);
            MethodInfo match = null;

            // XXX: what about out args, etc.?

            for (int i = 0; i < msig.Length; i++)
            {
                ParameterInfo[] pi = msig[i].GetParameters();
                if (pi.Length != plen)
                {
                    continue;
                }
                bool matched = true;
                for (int n = 0; n < pi.Length; n++)
                {
                    IntPtr p = Runtime.PyTuple_GetItem(args, n);
                    if (p == IntPtr.Zero)
                    {
                        Exceptions.Clear();
                        break;
                    }
                    ClassBase c = ManagedType.GetManagedObject(p) as ClassBase;
                    Type      t = (c != null) ? c.type :
                                  Converter.GetTypeByAlias(p);

                    if (t == null)
                    {
                        break;
                    }
                    if (t != pi[n].ParameterType)
                    {
                        matched = false;
                        break;
                    }
                }
                if (matched)
                {
                    match = msig[i];
                    break;
                }
            }

            if (free)
            {
                Runtime.Decref(args);
            }

            return(match);
        }
Пример #12
0
        internal static IntPtr CreateType(ManagedType impl, Type clrType)
        {
            // Cleanup the type name to get rid of funny nested type names.
            string name = "CLR." + clrType.FullName;
            int    i    = name.LastIndexOf('+');

            if (i > -1)
            {
                name = name.Substring(i + 1);
            }
            i = name.LastIndexOf('.');
            if (i > -1)
            {
                name = name.Substring(i + 1);
            }

            IntPtr base_   = IntPtr.Zero;
            int    ob_size = ObjectOffset.Size(Runtime.PyTypeType);

            // XXX Hack, use a different base class for System.Exception
            // Python 2.5+ allows new style class exceptions but they *must*
            // subclass BaseException (or better Exception).
            if (typeof(Exception).IsAssignableFrom(clrType))
            {
                ob_size = ObjectOffset.Size(Exceptions.Exception);
            }

            int tp_dictoffset = ob_size + ManagedDataOffsets.ob_dict;

            if (clrType == typeof(Exception))
            {
                base_ = Exceptions.Exception;
            }
            else if (clrType.BaseType != null)
            {
                ClassBase bc = ClassManager.GetClass(clrType.BaseType);
                base_ = bc.pyHandle;
            }

            IntPtr type = AllocateTypeObject(name);

            Marshal.WriteIntPtr(type, TypeOffset.ob_type, Runtime.PyCLRMetaType);
            Runtime.XIncref(Runtime.PyCLRMetaType);

            Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)ob_size);
            Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero);
            Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, (IntPtr)tp_dictoffset);

            // add a __len__ slot for inheritors of ICollection and ICollection<>
            if (typeof(ICollection).IsAssignableFrom(clrType) || clrType.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(ICollection <>)))
            {
                InitializeSlot(type, TypeOffset.mp_length, typeof(mp_length_slot).GetMethod(nameof(mp_length_slot.mp_length)));
            }

            // we want to do this after the slot stuff above in case the class itself implements a slot method
            InitializeSlots(type, impl.GetType());

            if (!typeof(IEnumerable).IsAssignableFrom(clrType) &&
                !typeof(IEnumerator).IsAssignableFrom(clrType))
            {
                // The tp_iter slot should only be set for enumerable types.
                Marshal.WriteIntPtr(type, TypeOffset.tp_iter, IntPtr.Zero);
            }


            // Only set mp_subscript and mp_ass_subscript for types with indexers
            if (impl is ClassBase cb)
            {
                if (!(impl is ArrayObject))
                {
                    if (cb.indexer == null || !cb.indexer.CanGet)
                    {
                        Marshal.WriteIntPtr(type, TypeOffset.mp_subscript, IntPtr.Zero);
                    }
                    if (cb.indexer == null || !cb.indexer.CanSet)
                    {
                        Marshal.WriteIntPtr(type, TypeOffset.mp_ass_subscript, IntPtr.Zero);
                    }
                }
            }
            else
            {
                Marshal.WriteIntPtr(type, TypeOffset.mp_subscript, IntPtr.Zero);
                Marshal.WriteIntPtr(type, TypeOffset.mp_ass_subscript, IntPtr.Zero);
            }

            if (base_ != IntPtr.Zero)
            {
                Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_);
                Runtime.XIncref(base_);
            }

            int flags = TypeFlags.Default;

            flags |= TypeFlags.Managed;
            flags |= TypeFlags.HeapType;
            flags |= TypeFlags.BaseType;
            flags |= TypeFlags.HaveGC;
            Util.WriteCLong(type, TypeOffset.tp_flags, flags);

            // Leverage followup initialization from the Python runtime. Note
            // that the type of the new type must PyType_Type at the time we
            // call this, else PyType_Ready will skip some slot initialization.

            Runtime.PyType_Ready(type);

            IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict);
            string mn   = clrType.Namespace ?? "";
            IntPtr mod  = Runtime.PyString_FromString(mn);

            Runtime.PyDict_SetItemString(dict, "__module__", mod);

            // Hide the gchandle of the implementation in a magic type slot.
            GCHandle gc = GCHandle.Alloc(impl);

            Marshal.WriteIntPtr(type, TypeOffset.magic(), (IntPtr)gc);

            // Set the handle attributes on the implementing instance.
            impl.tpHandle = Runtime.PyCLRMetaType;
            impl.gcHandle = gc;
            impl.pyHandle = type;

            //DebugUtil.DumpType(type);

            return(type);
        }
Пример #13
0
        internal static IntPtr CreateType(ManagedType impl, Type clrType)
        {
            // Cleanup the type name to get rid of funny nested type names.
            string name = "CLR." + clrType.FullName;
            int    i    = name.LastIndexOf('+');

            if (i > -1)
            {
                name = name.Substring(i + 1);
            }
            i = name.LastIndexOf('.');
            if (i > -1)
            {
                name = name.Substring(i + 1);
            }

            IntPtr base_ = IntPtr.Zero;

            if (clrType.BaseType != null)
            {
                ClassBase bc = ClassManager.GetClass(clrType.BaseType);
                base_ = bc.pyHandle;
            }

            IntPtr type = AllocateTypeObject(name);

            Marshal.WriteIntPtr(type, TypeOffset.ob_type, Runtime.PyCLRMetaType);
            Runtime.Incref(Runtime.PyCLRMetaType);

            Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)obSize);
            Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero);

            IntPtr offset = (IntPtr)ObjectOffset.ob_dict;

            Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset);

            InitializeSlots(type, impl.GetType());

            if (base_ != IntPtr.Zero)
            {
                Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_);
                Runtime.Incref(base_);
            }

            int flags = TypeFlags.Default;

            flags |= TypeFlags.Managed;
            flags |= TypeFlags.HeapType;
            flags |= TypeFlags.BaseType;
            flags |= TypeFlags.HaveGC;
            Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags);

            // Leverage followup initialization from the Python runtime. Note
            // that the type of the new type must PyType_Type at the time we
            // call this, else PyType_Ready will skip some slot initialization.

            Runtime.PyType_Ready(type);

            IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict);
            string mn   = clrType.Namespace != null ? clrType.Namespace : "";
            IntPtr mod  = Runtime.PyString_FromString(mn);

            Runtime.PyDict_SetItemString(dict, "__module__", mod);

            // Hide the gchandle of the implementation in a magic type slot.
            GCHandle gc = GCHandle.Alloc(impl);

            Marshal.WriteIntPtr(type, TypeOffset.magic(), (IntPtr)gc);

            // Set the handle attributes on the implementing instance.
            impl.tpHandle = Runtime.PyCLRMetaType;
            impl.gcHandle = gc;
            impl.pyHandle = type;

            //DebugUtil.DumpType(type);

            return(type);
        }
Пример #14
0
        public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw)
        {
            int len = Runtime.PyTuple_Size(args);

            if (len < 3)
            {
                return(Exceptions.RaiseTypeError("invalid argument list"));
            }

            IntPtr name  = Runtime.PyTuple_GetItem(args, 0);
            IntPtr bases = Runtime.PyTuple_GetItem(args, 1);
            IntPtr dict  = Runtime.PyTuple_GetItem(args, 2);

            // We do not support multiple inheritance, so the bases argument
            // should be a 1-item tuple containing the type we are subtyping.
            // That type must itself have a managed implementation. We check
            // that by making sure its metatype is the CLR metatype.

            if (Runtime.PyTuple_Size(bases) != 1)
            {
                return(Exceptions.RaiseTypeError(
                           "cannot use multiple inheritance with managed classes"
                           ));
            }

            IntPtr base_type = Runtime.PyTuple_GetItem(bases, 0);
            IntPtr mt        = Runtime.PyObject_TYPE(base_type);

            if (!((mt == PyCLRMetaType) || (mt == Runtime.PyTypeType)))
            {
                return(Exceptions.RaiseTypeError("invalid metatype"));
            }

            // Ensure that the reflected type is appropriate for subclassing,
            // disallowing subclassing of delegates, enums and array types.

            ClassBase cb = GetManagedObject(base_type) as ClassBase;

            if (cb != null)
            {
                if (!cb.CanSubclass())
                {
                    return(Exceptions.RaiseTypeError(
                               "delegates, enums and array types cannot be subclassed"
                               ));
                }
            }

            IntPtr slots = Runtime.PyDict_GetItemString(dict, "__slots__");

            if (slots != IntPtr.Zero)
            {
                return(Exceptions.RaiseTypeError(
                           "subclasses of managed classes do not support __slots__"
                           ));
            }

            // hack for now... fix for 1.0
            //return TypeManager.CreateSubType(args);


            // right way

            IntPtr func = Marshal.ReadIntPtr(Runtime.PyTypeType,
                                             TypeOffset.tp_new);
            IntPtr type = NativeCall.Call_3(func, tp, args, kw);

            if (type == IntPtr.Zero)
            {
                return(IntPtr.Zero);
            }

            int flags = TypeFlags.Default;

            flags |= TypeFlags.Managed;
            flags |= TypeFlags.HeapType;
            flags |= TypeFlags.BaseType;
            flags |= TypeFlags.Subclass;
            flags |= TypeFlags.HaveGC;
            Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags);

            TypeManager.CopySlot(base_type, type, TypeOffset.tp_dealloc);

            // Hmm - the standard subtype_traverse, clear look at ob_size to
            // do things, so to allow gc to work correctly we need to move
            // our hidden handle out of ob_size. Then, in theory we can
            // comment this out and still not crash.
            TypeManager.CopySlot(base_type, type, TypeOffset.tp_traverse);
            TypeManager.CopySlot(base_type, type, TypeOffset.tp_clear);


            // for now, move up hidden handle...
            IntPtr gc = Marshal.ReadIntPtr(base_type, TypeOffset.magic());

            Marshal.WriteIntPtr(type, TypeOffset.magic(), gc);

            //DebugUtil.DumpType(base_type);
            //DebugUtil.DumpType(type);

            return(type);
        }
Пример #15
0
        //====================================================================
        // MethodBinding  __call__ implementation.
        //====================================================================

        public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw)
        {
            MethodBinding self = (MethodBinding)GetManagedObject(ob);

            // This works around a situation where the wrong generic method is picked,
            // for example this method in the tests: string Overloaded<T>(int arg1, int arg2, string arg3)
            if (self.info != null)
            {
                if (self.info.IsGenericMethod)
                {
                    int    len   = Runtime.PyTuple_Size(args);
                    Type[] sigTp = Runtime.PythonArgsToTypeArray(args, true);
                    if (sigTp != null)
                    {
                        Type[]     genericTp   = self.info.GetGenericArguments();
                        MethodInfo betterMatch = MethodBinder.MatchSignatureAndParameters(self.m.info, genericTp, sigTp);
                        if (betterMatch != null)
                        {
                            self.info = betterMatch;
                        }
                    }
                }
            }

            // This supports calling a method 'unbound', passing the instance
            // as the first argument. Note that this is not supported if any
            // of the overloads are static since we can't know if the intent
            // was to call the static method or the unbound instance method.
            List <IntPtr> disposeList = new List <IntPtr>();

            try
            {
                IntPtr target = self.target;

                if ((target == IntPtr.Zero) && (!self.m.IsStatic()))
                {
                    int len = Runtime.PyTuple_Size(args);
                    if (len < 1)
                    {
                        Exceptions.SetError(Exceptions.TypeError, "not enough arguments");
                        return(IntPtr.Zero);
                    }
                    target = Runtime.PyTuple_GetItem(args, 0);
                    Runtime.Incref(target);
                    disposeList.Add(target);

                    args = Runtime.PyTuple_GetSlice(args, 1, len);
                    disposeList.Add(args);
                }

                // if the class is a IPythonDerivedClass and target is not the same as self.targetType
                // (eg if calling the base class method) then call the original base class method instead
                // of the target method.
                IntPtr superType = IntPtr.Zero;
                if (Runtime.PyObject_TYPE(target) != self.targetType)
                {
                    CLRObject inst = CLRObject.GetManagedObject(target) as CLRObject;
                    if (inst != null && (inst.inst as IPythonDerivedType) != null)
                    {
                        ClassBase baseType = GetManagedObject(self.targetType) as ClassBase;
                        if (baseType != null)
                        {
                            string baseMethodName = "_" + baseType.type.Name + "__" + self.m.name;
                            IntPtr baseMethod     = Runtime.PyObject_GetAttrString(target, baseMethodName);
                            if (baseMethod != IntPtr.Zero)
                            {
                                MethodBinding baseSelf = GetManagedObject(baseMethod) as MethodBinding;
                                if (baseSelf != null)
                                {
                                    self = baseSelf;
                                }
                                Runtime.Decref(baseMethod);
                            }
                            else
                            {
                                Runtime.PyErr_Clear();
                            }
                        }
                    }
                }

                return(self.m.Invoke(target, args, kw, self.info));
            }
            finally
            {
                foreach (IntPtr ptr in disposeList)
                {
                    Runtime.Decref(ptr);
                }
            }
        }
Пример #16
0
        internal static IntPtr CreateSubType(IntPtr py_name, IntPtr py_base_type, IntPtr 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;

            var disposeList = new List <PyObject>();

            try
            {
                var assemblyKey = new PyObject(Converter.ToPython("__assembly__", typeof(string)));
                disposeList.Add(assemblyKey);
                if (0 != Runtime.PyMapping_HasKey(py_dict, assemblyKey.Handle))
                {
                    var pyAssembly = new PyObject(Runtime.PyDict_GetItem(py_dict, assemblyKey.Handle));
                    Runtime.XIncref(pyAssembly.Handle);
                    disposeList.Add(pyAssembly);
                    if (!Converter.ToManagedValue(pyAssembly.Handle, typeof(string), out assembly, false))
                    {
                        throw new InvalidCastException("Couldn't convert __assembly__ value to string");
                    }
                }

                var namespaceKey = new PyObject(Converter.ToPythonImplicit("__namespace__"));
                disposeList.Add(namespaceKey);
                if (0 != Runtime.PyMapping_HasKey(py_dict, namespaceKey.Handle))
                {
                    var pyNamespace = new PyObject(Runtime.PyDict_GetItem(py_dict, namespaceKey.Handle));
                    Runtime.XIncref(pyNamespace.Handle);
                    disposeList.Add(pyNamespace);
                    if (!Converter.ToManagedValue(pyNamespace.Handle, typeof(string), out namespaceStr, false))
                    {
                        throw new InvalidCastException("Couldn't convert __namespace__ value to string");
                    }
                }
            }
            finally
            {
                foreach (PyObject o in disposeList)
                {
                    o.Dispose();
                }
            }

            // 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);
                Runtime.PyDict_Update(cls_dict, py_dict);

                return(py_type);
            }
            catch (Exception e)
            {
                return(Exceptions.RaiseTypeError(e.Message));
            }
        }
Пример #17
0
        internal static CLRObject GetInstance(object ob)
        {
            ClassBase cc = ClassManager.GetClass(ob.GetType());

            return(GetInstance(ob, cc.tpHandle));
        }
Пример #18
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;

            // 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.
            IntPtr dict = Marshal.ReadIntPtr(tp, TypeOffset.tp_dict);


            IDictionaryEnumerator iter = info.members.GetEnumerator();

            while (iter.MoveNext())
            {
                var item = (ManagedType)iter.Value;
                var name = (string)iter.Key;
                Runtime.PyDict_SetItemString(dict, name, item.pyHandle);
                // Decref the item now that it's been used.
                item.DecrRefCount();
            }

            // If class has constructors, generate an __doc__ attribute.
            IntPtr doc    = IntPtr.Zero;
            Type   marker = typeof(DocStringAttribute);
            var    attrs  = (Attribute[])type.GetCustomAttributes(marker, false);

            if (attrs.Length == 0)
            {
                doc = IntPtr.Zero;
            }
            else
            {
                var    attr   = (DocStringAttribute)attrs[0];
                string docStr = attr.DocString;
                doc = Runtime.PyString_FromString(docStr);
                Runtime.PyDict_SetItem(dict, PyIdentifier.__doc__, doc);
                Runtime.XDecref(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.ctors.Length > 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.pyHandle);
                        Runtime.PyDict_SetItem(dict, PyIdentifier.Overloads, ctors.pyHandle);
                        ctors.DecrRefCount();
                    }

                    // don't generate the docstring if one was already set from a DocStringAttribute.
                    if (!CLRModule._SuppressDocs && doc == IntPtr.Zero)
                    {
                        doc = co.GetDocString();
                        Runtime.PyDict_SetItem(dict, PyIdentifier.__doc__, doc);
                        Runtime.XDecref(doc);
                    }
                }
            }
        }