Example #1
0
        /// <summary>
        /// Metatype __call__ implementation. This is needed to ensure correct
        /// initialization (__init__ support), because the tp_call we inherit
        /// from PyType_Type won't call __init__ for metatypes it doesn't know.
        /// </summary>
        public static IntPtr tp_call(IntPtr tp, IntPtr args, IntPtr kw)
        {
            IntPtr func = Marshal.ReadIntPtr(tp, TypeOffset.tp_new);

            if (func == IntPtr.Zero)
            {
                return(Exceptions.RaiseTypeError("invalid object"));
            }

            IntPtr obj = NativeCall.Call_3(func, tp, args, kw);

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

            var init = Runtime.PyObject_GetAttrString(obj, "__init__");

            Runtime.PyErr_Clear();

            if (init != IntPtr.Zero)
            {
                IntPtr result = Runtime.PyObject_Call(init, args, kw);
                Runtime.XDecref(init);

                if (result == IntPtr.Zero)
                {
                    Runtime.XDecref(obj);
                    return(IntPtr.Zero);
                }

                Runtime.XDecref(result);
            }

            return(obj);
        }
Example #2
0
        /// <summary>
        /// Implement binding of generic methods using the subscript syntax [].
        /// </summary>
        public static IntPtr mp_subscript(IntPtr tp, IntPtr idx)
        {
            var self = (MethodBinding)GetManagedObject(tp);

            Type[] types = Runtime.PythonArgsToTypeArray(idx);
            if (types == null)
            {
                return(Exceptions.RaiseTypeError("type(s) expected"));
            }

            MethodInfo mi = MethodBinder.MatchParameters(self.m.info, types);

            if (mi == null)
            {
                return(Exceptions.RaiseTypeError("No match found for given type params"));
            }

            var mb = new MethodBinding(self.m, self.target)
            {
                info = mi
            };

            return(mb.pyHandle);
        }
Example #3
0
        /// <summary>
        /// The actual import hook that ties Python to the managed world.
        /// </summary>
        public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw)
        {
            // Replacement for the builtin __import__. The original import
            // hook is saved as this.py_import. This version handles CLR
            // import and defers to the normal builtin for everything else.

            var num_args = Runtime.PyTuple_Size(args);

            if (num_args < 1)
            {
                return(Exceptions.RaiseTypeError("__import__() takes at least 1 argument (0 given)"));
            }

            // borrowed reference
            IntPtr py_mod_name = Runtime.PyTuple_GetItem(args, 0);

            if (py_mod_name == IntPtr.Zero ||
                !Runtime.IsStringType(py_mod_name))
            {
                return(Exceptions.RaiseTypeError("string expected"));
            }

            // Check whether the import is of the form 'from x import y'.
            // This determines whether we return the head or tail module.

            IntPtr fromList = IntPtr.Zero;
            var    fromlist = false;

            if (num_args >= 4)
            {
                fromList = Runtime.PyTuple_GetItem(args, 3);
                if (fromList != IntPtr.Zero &&
                    Runtime.PyObject_IsTrue(fromList) == 1)
                {
                    fromlist = true;
                }
            }

            string mod_name = Runtime.GetManagedString(py_mod_name);

            // Check these BEFORE the built-in import runs; may as well
            // do the Incref()ed return here, since we've already found
            // the module.
            if (mod_name == "clr")
            {
                IntPtr clr_module = GetCLRModule(fromList);
                if (clr_module != IntPtr.Zero)
                {
                    IntPtr sys_modules = Runtime.PyImport_GetModuleDict();
                    if (sys_modules != IntPtr.Zero)
                    {
                        Runtime.PyDict_SetItemString(sys_modules, "clr", clr_module);
                    }
                }
                return(clr_module);
            }
            if (mod_name == "CLR")
            {
                Exceptions.deprecation("The CLR module is deprecated. Please use 'clr'.");
                IntPtr clr_module = GetCLRModule(fromList);
                if (clr_module != IntPtr.Zero)
                {
                    IntPtr sys_modules = Runtime.PyImport_GetModuleDict();
                    if (sys_modules != IntPtr.Zero)
                    {
                        Runtime.PyDict_SetItemString(sys_modules, "clr", clr_module);
                    }
                }
                return(clr_module);
            }
            string realname   = mod_name;
            string clr_prefix = null;

            if (mod_name.StartsWith("CLR."))
            {
                clr_prefix = "CLR."; // prepend when adding the module to sys.modules
                realname   = mod_name.Substring(4);
                string msg = $"Importing from the CLR.* namespace is deprecated. Please import '{realname}' directly.";
                Exceptions.deprecation(msg);
            }
            else
            {
                // 2010-08-15: Always seemed smart to let python try first...
                // This shaves off a few tenths of a second on test_module.py
                // and works around a quirk where 'sys' is found by the
                // LoadImplicit() deprecation logic.
                // Turns out that the AssemblyManager.ResolveHandler() checks to see if any
                // Assembly's FullName.ToLower().StartsWith(name.ToLower()), which makes very
                // little sense to me.
                IntPtr res = Runtime.PyObject_Call(py_import, args, kw);
                if (res != IntPtr.Zero)
                {
                    // There was no error.
                    if (fromlist && IsLoadAll(fromList))
                    {
                        var mod = ManagedType.GetManagedObject(res) as ModuleObject;
                        mod?.LoadNames();
                    }
                    return(res);
                }
                // There was an error
                if (!Exceptions.ExceptionMatches(Exceptions.ImportError))
                {
                    // and it was NOT an ImportError; bail out here.
                    return(IntPtr.Zero);
                }

                if (mod_name == string.Empty)
                {
                    // Most likely a missing relative import.
                    // For example site-packages\bs4\builder\__init__.py uses it to check if a package exists:
                    //     from . import _html5lib
                    // We don't support them anyway
                    return(IntPtr.Zero);
                }
                // Otherwise,  just clear the it.
                Exceptions.Clear();
            }

            string[] names = realname.Split('.');

            // Now we need to decide if the name refers to a CLR module,
            // and may have to do an implicit load (for b/w compatibility)
            // using the AssemblyManager. The assembly manager tries
            // really hard not to use Python objects or APIs, because
            // parts of it can run recursively and on strange threads.
            //
            // It does need an opportunity from time to time to check to
            // see if sys.path has changed, in a context that is safe. Here
            // we know we have the GIL, so we'll let it update if needed.

            AssemblyManager.UpdatePath();
            if (!AssemblyManager.IsValidNamespace(realname))
            {
                if (!AssemblyManager.LoadImplicit(realname))
                {
                    // May be called when a module being imported imports a module.
                    // In particular, I've seen decimal import copy import org.python.core
                    return(Runtime.PyObject_Call(py_import, args, kw));
                }
            }

            // See if sys.modules for this interpreter already has the
            // requested module. If so, just return the existing module.
            IntPtr modules = Runtime.PyImport_GetModuleDict();
            IntPtr module  = Runtime.PyDict_GetItem(modules, py_mod_name);

            if (module != IntPtr.Zero)
            {
                if (fromlist)
                {
                    if (IsLoadAll(fromList))
                    {
                        var mod = ManagedType.GetManagedObject(module) as ModuleObject;
                        mod?.LoadNames();
                    }
                    Runtime.XIncref(module);
                    return(module);
                }
                if (clr_prefix != null)
                {
                    return(GetCLRModule(fromList));
                }
                module = Runtime.PyDict_GetItemString(modules, names[0]);
                Runtime.XIncref(module);
                return(module);
            }
            Exceptions.Clear();

            // Traverse the qualified module name to get the named module
            // and place references in sys.modules as we go. Note that if
            // we are running in interactive mode we pre-load the names in
            // each module, which is often useful for introspection. If we
            // are not interactive, we stick to just-in-time creation of
            // objects at lookup time, which is much more efficient.
            // NEW: The clr got a new module variable preload. You can
            // enable preloading in a non-interactive python processing by
            // setting clr.preload = True

            ModuleObject head = mod_name == realname ? null : root;
            ModuleObject tail = root;

            root.InitializePreload();

            foreach (string name in names)
            {
                ManagedType mt = tail.GetAttribute(name, true);
                if (!(mt is ModuleObject))
                {
                    Exceptions.SetError(Exceptions.ImportError, $"No module named {name}");
                    return(IntPtr.Zero);
                }
                if (head == null)
                {
                    head = (ModuleObject)mt;
                }
                tail = (ModuleObject)mt;
                if (CLRModule.preload)
                {
                    tail.LoadNames();
                }

                // Add the module to sys.modules
                Runtime.PyDict_SetItemString(modules, tail.moduleName, tail.pyHandle);

                // If imported from CLR add CLR.<modulename> to sys.modules as well
                if (clr_prefix != null)
                {
                    Runtime.PyDict_SetItemString(modules, clr_prefix + tail.moduleName, tail.pyHandle);
                }
            }

            {
                var mod = fromlist ? tail : head;

                if (fromlist && IsLoadAll(fromList))
                {
                    mod.LoadNames();
                }

                Runtime.XIncref(mod.pyHandle);
                return(mod.pyHandle);
            }
        }
Example #4
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));
            }
        }
Example #5
0
        /// <summary>
        /// Metatype __new__ implementation. This is called to create a new
        /// class / type when a reflected class is subclassed.
        /// </summary>
        public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw)
        {
            var 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.

            var 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__"));
            }

            // If __assembly__ or __namespace__ are in the class dictionary then create
            // a managed sub type.
            // This creates a new managed type that can be used from .net to call back
            // into python.
            if (IntPtr.Zero != dict)
            {
                Runtime.XIncref(dict);
                using (var clsDict = new PyDict(dict)) {
                    if (clsDict.HasKey("__assembly__") || clsDict.HasKey("__namespace__"))
                    {
                        return(TypeManager.CreateSubType(name, base_type, dict));
                    }
                }
            }

            // otherwise just create a basic type without reflecting back into the managed side.
            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;
            Util.WriteCLong(type, TypeOffset.tp_flags, 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);

            return(type);
        }
Example #6
0
        /// <summary>
        /// Standard comparison implementation for instances of reflected types.
        /// </summary>
        public static IntPtr tp_richcompare(IntPtr ob, IntPtr other, int op)
        {
            CLRObject co1;
            CLRObject co2;

            switch (op)
            {
            case Runtime.Py_EQ:
            case Runtime.Py_NE:
                IntPtr pytrue  = Runtime.PyTrue;
                IntPtr pyfalse = Runtime.PyFalse;

                // swap true and false for NE
                if (op != Runtime.Py_EQ)
                {
                    pytrue  = Runtime.PyFalse;
                    pyfalse = Runtime.PyTrue;
                }

                if (ob == other)
                {
                    Runtime.XIncref(pytrue);
                    return(pytrue);
                }

                co1 = GetManagedObject(ob) as CLRObject;
                co2 = GetManagedObject(other) as CLRObject;
                if (null == co2)
                {
                    Runtime.XIncref(pyfalse);
                    return(pyfalse);
                }

                object o1 = co1.inst;
                object o2 = co2.inst;

                if (Equals(o1, o2))
                {
                    Runtime.XIncref(pytrue);
                    return(pytrue);
                }

                Runtime.XIncref(pyfalse);
                return(pyfalse);

            case Runtime.Py_LT:
            case Runtime.Py_LE:
            case Runtime.Py_GT:
            case Runtime.Py_GE:
                co1 = GetManagedObject(ob) as CLRObject;
                co2 = GetManagedObject(other) as CLRObject;
                if (co1 == null || co2 == null)
                {
                    return(Exceptions.RaiseTypeError("Cannot get managed object"));
                }
                var co1Comp = co1.inst as IComparable;
                if (co1Comp == null)
                {
                    Type co1Type = co1.GetType();
                    return(Exceptions.RaiseTypeError($"Cannot convert object of type {co1Type} to IComparable"));
                }
                try {
                    int cmp = co1Comp.CompareTo(co2.inst);

                    IntPtr pyCmp;
                    if (cmp < 0)
                    {
                        if (op == Runtime.Py_LT || op == Runtime.Py_LE)
                        {
                            pyCmp = Runtime.PyTrue;
                        }
                        else
                        {
                            pyCmp = Runtime.PyFalse;
                        }
                    }
                    else if (cmp == 0)
                    {
                        if (op == Runtime.Py_LE || op == Runtime.Py_GE)
                        {
                            pyCmp = Runtime.PyTrue;
                        }
                        else
                        {
                            pyCmp = Runtime.PyFalse;
                        }
                    }
                    else
                    {
                        if (op == Runtime.Py_GE || op == Runtime.Py_GT)
                        {
                            pyCmp = Runtime.PyTrue;
                        }
                        else
                        {
                            pyCmp = Runtime.PyFalse;
                        }
                    }
                    Runtime.XIncref(pyCmp);
                    return(pyCmp);
                }
                catch (ArgumentException e) {
                    return(Exceptions.RaiseTypeError(e.Message));
                }

            default:
                Runtime.XIncref(Runtime.PyNotImplemented);
                return(Runtime.PyNotImplemented);
            }
        }
Example #7
0
        /// <summary>
        /// Implements __getitem__ for array types.
        /// </summary>
        public static IntPtr mp_subscript(IntPtr ob, IntPtr idx)
        {
            var    obj      = (CLRObject)GetManagedObject(ob);
            var    items    = obj.inst as Array;
            Type   itemType = obj.inst.GetType().GetElementType();
            int    rank     = items.Rank;
            int    index;
            object value;

            // Note that CLR 1.0 only supports int indexes - methods to
            // support long indices were introduced in 1.1. We could
            // support long indices automatically, but given that long
            // indices are not backward compatible and a relative edge
            // case, we won't bother for now.

            // Single-dimensional arrays are the most common case and are
            // cheaper to deal with than multi-dimensional, so check first.

            if (rank == 1)
            {
                index = Runtime.PyInt_AsLong(idx);

                if (Exceptions.ErrorOccurred())
                {
                    return(Exceptions.RaiseTypeError("invalid index value"));
                }

                if (index < 0)
                {
                    index = items.Length + index;
                }

                try {
                    value = items.GetValue(index);
                }
                catch (IndexOutOfRangeException) {
                    Exceptions.SetError(Exceptions.IndexError, "array index out of range");
                    return(IntPtr.Zero);
                }

                return(Converter.ToPython(value, itemType));
            }

            // Multi-dimensional arrays can be indexed a la: list[1, 2, 3].

            if (!Runtime.PyTuple_Check(idx))
            {
                Exceptions.SetError(Exceptions.TypeError, "invalid index value");
                return(IntPtr.Zero);
            }

            var count = Runtime.PyTuple_Size(idx);

            var args = new int[count];

            for (var i = 0; i < count; i++)
            {
                IntPtr op = Runtime.PyTuple_GetItem(idx, i);
                index = Runtime.PyInt_AsLong(op);

                if (Exceptions.ErrorOccurred())
                {
                    return(Exceptions.RaiseTypeError("invalid index value"));
                }

                if (index < 0)
                {
                    index = items.GetLength(i) + index;
                }

                args.SetValue(index, i);
            }

            try {
                value = items.GetValue(args);
            }
            catch (IndexOutOfRangeException) {
                Exceptions.SetError(Exceptions.IndexError, "array index out of range");
                return(IntPtr.Zero);
            }

            return(Converter.ToPython(value, itemType));
        }
Example #8
0
        /// <summary>
        /// Implements __setitem__ for array types.
        /// </summary>
        public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v)
        {
            var    obj      = (CLRObject)GetManagedObject(ob);
            var    items    = obj.inst as Array;
            Type   itemType = obj.inst.GetType().GetElementType();
            int    rank     = items.Rank;
            int    index;
            object value;

            if (items.IsReadOnly)
            {
                Exceptions.RaiseTypeError("array is read-only");
                return(-1);
            }

            if (!Converter.ToManaged(v, itemType, out value, true))
            {
                return(-1);
            }

            if (rank == 1)
            {
                index = Runtime.PyInt_AsLong(idx);

                if (Exceptions.ErrorOccurred())
                {
                    Exceptions.RaiseTypeError("invalid index value");
                    return(-1);
                }

                if (index < 0)
                {
                    index = items.Length + index;
                }

                try {
                    items.SetValue(value, index);
                }
                catch (IndexOutOfRangeException) {
                    Exceptions.SetError(Exceptions.IndexError, "array index out of range");
                    return(-1);
                }

                return(0);
            }

            if (!Runtime.PyTuple_Check(idx))
            {
                Exceptions.RaiseTypeError("invalid index value");
                return(-1);
            }

            var count = Runtime.PyTuple_Size(idx);
            var args  = new int[count];

            for (var i = 0; i < count; i++)
            {
                IntPtr op = Runtime.PyTuple_GetItem(idx, i);
                index = Runtime.PyInt_AsLong(op);

                if (Exceptions.ErrorOccurred())
                {
                    Exceptions.RaiseTypeError("invalid index value");
                    return(-1);
                }

                if (index < 0)
                {
                    index = items.GetLength(i) + index;
                }

                args.SetValue(index, i);
            }

            try {
                items.SetValue(value, args);
            }
            catch (IndexOutOfRangeException) {
                Exceptions.SetError(Exceptions.IndexError, "array index out of range");
                return(-1);
            }

            return(0);
        }
Example #9
0
        /// <summary>
        /// Descriptor __set__ implementation. This method sets the value of
        /// a property based on the given Python value. The Python value must
        /// be convertible to the type of the property.
        /// </summary>
        public new static int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val)
        {
            var        self   = (PropertyObject)GetManagedObject(ds);
            MethodInfo setter = self.setter;
            object     newval;

            if (val == IntPtr.Zero)
            {
                Exceptions.RaiseTypeError("cannot delete property");
                return(-1);
            }

            if (setter == null)
            {
                Exceptions.RaiseTypeError("property is read-only");
                return(-1);
            }


            if (!Converter.ToManaged(val, self.info.PropertyType, out newval, true))
            {
                return(-1);
            }

            bool is_static = setter.IsStatic;

            if (ob == IntPtr.Zero || ob == Runtime.PyNone)
            {
                if (!is_static)
                {
                    Exceptions.RaiseTypeError("instance property must be set on an instance");
                    return(-1);
                }
            }

            try {
                if (!is_static)
                {
                    var co = GetManagedObject(ob) as CLRObject;
                    if (co == null)
                    {
                        Exceptions.RaiseTypeError("invalid target");
                        return(-1);
                    }
                    self.info.SetValue(co.inst, newval, null);
                }
                else
                {
                    self.info.SetValue(null, newval, null);
                }
                return(0);
            }
            catch (Exception e) {
                if (e.InnerException != null)
                {
                    e = e.InnerException;
                }
                Exceptions.SetError(e);
                return(-1);
            }
        }