Beispiel #1
0
        /// <summary>
        /// Convert a Python value to an instance of a primitive managed type.
        /// </summary>
        private static bool ToPrimitive(IntPtr value, Type obType, out object result, bool setError)
        {
            IntPtr   overflow = Exceptions.OverflowError;
            TypeCode tc       = Type.GetTypeCode(obType);

            result = null;
            IntPtr op;
            int    ival;

            switch (tc)
            {
            case TypeCode.String:
                string st = Runtime.GetManagedString(value);
                if (st == null)
                {
                    goto type_error;
                }
                result = st;
                return(true);

            case TypeCode.Int32:
                // Trickery to support 64-bit platforms.
                if (Runtime.IsPython2 && Runtime.Is32Bit)
                {
                    op = Runtime.PyNumber_Int(value);

                    // As of Python 2.3, large ints magically convert :(
                    if (Runtime.PyLong_Check(op))
                    {
                        Runtime.XDecref(op);
                        goto overflow;
                    }

                    if (op == IntPtr.Zero)
                    {
                        if (Exceptions.ExceptionMatches(overflow))
                        {
                            goto overflow;
                        }
                        goto type_error;
                    }
                    ival = (int)Runtime.PyInt_AsLong(op);
                    Runtime.XDecref(op);
                    result = ival;
                    return(true);
                }
                else     // Python3 always use PyLong API
                {
                    op = Runtime.PyNumber_Long(value);
                    if (op == IntPtr.Zero)
                    {
                        Exceptions.Clear();
                        if (Exceptions.ExceptionMatches(overflow))
                        {
                            goto overflow;
                        }
                        goto type_error;
                    }
                    long ll = (long)Runtime.PyLong_AsLongLong(op);
                    Runtime.XDecref(op);
                    if (ll == -1 && Exceptions.ErrorOccurred())
                    {
                        goto overflow;
                    }
                    if (ll > Int32.MaxValue || ll < Int32.MinValue)
                    {
                        goto overflow;
                    }
                    result = (int)ll;
                    return(true);
                }

            case TypeCode.Boolean:
                result = Runtime.PyObject_IsTrue(value) != 0;
                return(true);

            case TypeCode.Byte:
#if PYTHON3
                if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType))
                {
                    if (Runtime.PyBytes_Size(value) == 1)
                    {
                        op     = Runtime.PyBytes_AS_STRING(value);
                        result = (byte)Marshal.ReadByte(op);
                        return(true);
                    }
                    goto type_error;
                }
#elif PYTHON2
                if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType))
                {
                    if (Runtime.PyString_Size(value) == 1)
                    {
                        op     = Runtime.PyString_AsString(value);
                        result = (byte)Marshal.ReadByte(op);
                        return(true);
                    }
                    goto type_error;
                }
#endif

                op = Runtime.PyNumber_Int(value);
                if (op == IntPtr.Zero)
                {
                    if (Exceptions.ExceptionMatches(overflow))
                    {
                        goto overflow;
                    }
                    goto type_error;
                }
                ival = (int)Runtime.PyInt_AsLong(op);
                Runtime.XDecref(op);

                if (ival > Byte.MaxValue || ival < Byte.MinValue)
                {
                    goto overflow;
                }
                byte b = (byte)ival;
                result = b;
                return(true);

            case TypeCode.SByte:
#if PYTHON3
                if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType))
                {
                    if (Runtime.PyBytes_Size(value) == 1)
                    {
                        op     = Runtime.PyBytes_AS_STRING(value);
                        result = (byte)Marshal.ReadByte(op);
                        return(true);
                    }
                    goto type_error;
                }
#elif PYTHON2
                if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType))
                {
                    if (Runtime.PyString_Size(value) == 1)
                    {
                        op     = Runtime.PyString_AsString(value);
                        result = (sbyte)Marshal.ReadByte(op);
                        return(true);
                    }
                    goto type_error;
                }
#endif

                op = Runtime.PyNumber_Int(value);
                if (op == IntPtr.Zero)
                {
                    if (Exceptions.ExceptionMatches(overflow))
                    {
                        goto overflow;
                    }
                    goto type_error;
                }
                ival = (int)Runtime.PyInt_AsLong(op);
                Runtime.XDecref(op);

                if (ival > SByte.MaxValue || ival < SByte.MinValue)
                {
                    goto overflow;
                }
                sbyte sb = (sbyte)ival;
                result = sb;
                return(true);

            case TypeCode.Char:
#if PYTHON3
                if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType))
                {
                    if (Runtime.PyBytes_Size(value) == 1)
                    {
                        op     = Runtime.PyBytes_AS_STRING(value);
                        result = (byte)Marshal.ReadByte(op);
                        return(true);
                    }
                    goto type_error;
                }
#elif PYTHON2
                if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType))
                {
                    if (Runtime.PyString_Size(value) == 1)
                    {
                        op     = Runtime.PyString_AsString(value);
                        result = (char)Marshal.ReadByte(op);
                        return(true);
                    }
                    goto type_error;
                }
#endif
                else if (Runtime.PyObject_TypeCheck(value, Runtime.PyUnicodeType))
                {
                    if (Runtime.PyUnicode_GetSize(value) == 1)
                    {
                        op = Runtime.PyUnicode_AsUnicode(value);
                        Char[] buff = new Char[1];
                        Marshal.Copy(op, buff, 0, 1);
                        result = buff[0];
                        return(true);
                    }
                    goto type_error;
                }

                op = Runtime.PyNumber_Int(value);
                if (op == IntPtr.Zero)
                {
                    goto type_error;
                }
                ival = Runtime.PyInt_AsLong(op);
                Runtime.XDecref(op);
                if (ival > Char.MaxValue || ival < Char.MinValue)
                {
                    goto overflow;
                }
                result = (char)ival;
                return(true);

            case TypeCode.Int16:
                op = Runtime.PyNumber_Int(value);
                if (op == IntPtr.Zero)
                {
                    if (Exceptions.ExceptionMatches(overflow))
                    {
                        goto overflow;
                    }
                    goto type_error;
                }
                ival = (int)Runtime.PyInt_AsLong(op);
                Runtime.XDecref(op);
                if (ival > Int16.MaxValue || ival < Int16.MinValue)
                {
                    goto overflow;
                }
                short s = (short)ival;
                result = s;
                return(true);

            case TypeCode.Int64:
                op = Runtime.PyNumber_Long(value);
                if (op == IntPtr.Zero)
                {
                    if (Exceptions.ExceptionMatches(overflow))
                    {
                        goto overflow;
                    }
                    goto type_error;
                }
                long l = (long)Runtime.PyLong_AsLongLong(op);
                Runtime.XDecref(op);
                if ((l == -1) && Exceptions.ErrorOccurred())
                {
                    goto overflow;
                }
                result = l;
                return(true);

            case TypeCode.UInt16:
                op = Runtime.PyNumber_Int(value);
                if (op == IntPtr.Zero)
                {
                    if (Exceptions.ExceptionMatches(overflow))
                    {
                        goto overflow;
                    }
                    goto type_error;
                }
                ival = (int)Runtime.PyInt_AsLong(op);
                Runtime.XDecref(op);
                if (ival > UInt16.MaxValue || ival < UInt16.MinValue)
                {
                    goto overflow;
                }
                ushort us = (ushort)ival;
                result = us;
                return(true);

            case TypeCode.UInt32:
                op = Runtime.PyNumber_Long(value);
                if (op == IntPtr.Zero)
                {
                    if (Exceptions.ExceptionMatches(overflow))
                    {
                        goto overflow;
                    }
                    goto type_error;
                }
                uint ui = (uint)Runtime.PyLong_AsUnsignedLong(op);

                if (Exceptions.ErrorOccurred())
                {
                    Runtime.XDecref(op);
                    goto overflow;
                }

                IntPtr check = Runtime.PyLong_FromUnsignedLong(ui);
                int    err   = Runtime.PyObject_Compare(check, op);
                Runtime.XDecref(check);
                Runtime.XDecref(op);
                if (0 != err || Exceptions.ErrorOccurred())
                {
                    goto overflow;
                }

                result = ui;
                return(true);

            case TypeCode.UInt64:
                op = Runtime.PyNumber_Long(value);
                if (op == IntPtr.Zero)
                {
                    if (Exceptions.ExceptionMatches(overflow))
                    {
                        goto overflow;
                    }
                    goto type_error;
                }
                ulong ul = (ulong)Runtime.PyLong_AsUnsignedLongLong(op);
                Runtime.XDecref(op);
                if (Exceptions.ErrorOccurred())
                {
                    goto overflow;
                }
                result = ul;
                return(true);


            case TypeCode.Single:
                op = Runtime.PyNumber_Float(value);
                if (op == IntPtr.Zero)
                {
                    if (Exceptions.ExceptionMatches(overflow))
                    {
                        goto overflow;
                    }
                    goto type_error;
                }
                double dd = Runtime.PyFloat_AsDouble(op);
                Runtime.CheckExceptionOccurred();
                Runtime.XDecref(op);
                if (dd > Single.MaxValue || dd < Single.MinValue)
                {
                    if (!double.IsInfinity(dd))
                    {
                        goto overflow;
                    }
                }
                result = (float)dd;
                return(true);

            case TypeCode.Double:
                op = Runtime.PyNumber_Float(value);
                if (op == IntPtr.Zero)
                {
                    goto type_error;
                }
                double d = Runtime.PyFloat_AsDouble(op);
                Runtime.CheckExceptionOccurred();
                Runtime.XDecref(op);
                result = d;
                return(true);
            }


type_error:

            if (setError)
            {
                string tpName = Runtime.PyObject_GetTypeName(value);
                Exceptions.SetError(Exceptions.TypeError, $"'{tpName}' value cannot be converted to {obType}");
            }

            return(false);

overflow:

            if (setError)
            {
                Exceptions.SetError(Exceptions.OverflowError, "value too large to convert");
            }

            return(false);
        }
Beispiel #2
0
        internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, MethodInfo[] methodinfo)
        {
            Binding binding = Bind(inst, args, kw, info, methodinfo);
            object  result;
            IntPtr  ts = IntPtr.Zero;

            if (binding == null)
            {
                var value = "No method matches given arguments";
                if (methodinfo != null && methodinfo.Length > 0)
                {
                    value += $" for {methodinfo[0].Name}";
                }
                Exceptions.SetError(Exceptions.TypeError, value);
                return(IntPtr.Zero);
            }

            if (allow_threads)
            {
                ts = PythonEngine.BeginAllowThreads();
            }

            try {
                result = binding.info.Invoke(binding.inst, BindingFlags.Default, null, binding.args, null);
            }
            catch (Exception e) {
                if (e.InnerException != null)
                {
                    e = e.InnerException;
                }
                if (allow_threads)
                {
                    PythonEngine.EndAllowThreads(ts);
                }
                Exceptions.SetError(e);
                return(IntPtr.Zero);
            }

            if (allow_threads)
            {
                PythonEngine.EndAllowThreads(ts);
            }

            // If there are out parameters, we return a tuple containing
            // the result followed by the out parameters. If there is only
            // one out parameter and the return type of the method is void,
            // we return the out parameter as the result to Python (for
            // code compatibility with ironpython).

            var mi = (MethodInfo)binding.info;

            if (binding.outs == 1 && mi.ReturnType == typeof(void))
            {
            }

            if (binding.outs > 0)
            {
                ParameterInfo[] pi = mi.GetParameters();
                int             c  = pi.Length;
                var             n  = 0;

                IntPtr t = Runtime.PyTuple_New(binding.outs + 1);
                IntPtr v = Converter.ToPython(result, mi.ReturnType);
                Runtime.PyTuple_SetItem(t, n, v);
                n++;

                for (var i = 0; i < c; i++)
                {
                    Type pt = pi[i].ParameterType;
                    if (pi[i].IsOut || pt.IsByRef)
                    {
                        v = Converter.ToPython(binding.args[i], pt);
                        Runtime.PyTuple_SetItem(t, n, v);
                        n++;
                    }
                }

                if (binding.outs == 1 && mi.ReturnType == typeof(void))
                {
                    v = Runtime.PyTuple_GetItem(t, 1);
                    Runtime.XIncref(v);
                    Runtime.XDecref(t);
                    return(v);
                }

                return(t);
            }

            return(Converter.ToPython(result, mi.ReturnType));
        }
Beispiel #3
0
        internal static bool ToManagedValue(IntPtr value, Type obType,
                                            out object result, bool setError)
        {
            if (obType == typeof(PyObject))
            {
                Runtime.XIncref(value); // PyObject() assumes ownership
                result = new PyObject(value);
                return(true);
            }

            // Common case: if the Python value is a wrapped managed object
            // instance, just return the wrapped object.
            ManagedType mt = ManagedType.GetManagedObject(value);

            result = null;

            if (mt != null)
            {
                if (mt is CLRObject)
                {
                    object tmp = ((CLRObject)mt).inst;
                    if (obType.IsInstanceOfType(tmp))
                    {
                        result = tmp;
                        return(true);
                    }
                    Exceptions.SetError(Exceptions.TypeError, $"value cannot be converted to {obType}");
                    return(false);
                }
                if (mt is ClassBase)
                {
                    result = ((ClassBase)mt).type;
                    return(true);
                }
                // shouldn't happen
                return(false);
            }

            if (value == Runtime.PyNone && !obType.IsValueType)
            {
                result = null;
                return(true);
            }

            if (obType.IsGenericType && obType.GetGenericTypeDefinition() == typeof(Nullable <>))
            {
                if (value == Runtime.PyNone)
                {
                    result = null;
                    return(true);
                }
                // Set type to underlying type
                obType = obType.GetGenericArguments()[0];
            }

            if (obType.IsArray)
            {
                return(ToArray(value, obType, out result, setError));
            }

            if (obType.IsEnum)
            {
                return(ToEnum(value, obType, out result, setError));
            }

            // Conversion to 'Object' is done based on some reasonable default
            // conversions (Python string -> managed string, Python int -> Int32 etc.).
            if (obType == objectType)
            {
                if (Runtime.IsStringType(value))
                {
                    return(ToPrimitive(value, stringType, out result, setError));
                }

                if (Runtime.PyBool_Check(value))
                {
                    return(ToPrimitive(value, boolType, out result, setError));
                }

                if (Runtime.PyInt_Check(value))
                {
                    return(ToPrimitive(value, int32Type, out result, setError));
                }

                if (Runtime.PyLong_Check(value))
                {
                    return(ToPrimitive(value, int64Type, out result, setError));
                }

                if (Runtime.PyFloat_Check(value))
                {
                    return(ToPrimitive(value, doubleType, out result, setError));
                }

                if (Runtime.PySequence_Check(value))
                {
                    return(ToArray(value, typeof(object[]), out result, setError));
                }

                if (setError)
                {
                    Exceptions.SetError(Exceptions.TypeError, "value cannot be converted to Object");
                }

                return(false);
            }

            // Conversion to 'Type' is done using the same mappings as above for objects.
            if (obType == typeType)
            {
                if (value == Runtime.PyStringType)
                {
                    result = stringType;
                    return(true);
                }

                if (value == Runtime.PyBoolType)
                {
                    result = boolType;
                    return(true);
                }

                if (value == Runtime.PyIntType)
                {
                    result = int32Type;
                    return(true);
                }

                if (value == Runtime.PyLongType)
                {
                    result = int64Type;
                    return(true);
                }

                if (value == Runtime.PyFloatType)
                {
                    result = doubleType;
                    return(true);
                }

                if (value == Runtime.PyListType || value == Runtime.PyTupleType)
                {
                    result = typeof(object[]);
                    return(true);
                }

                if (setError)
                {
                    Exceptions.SetError(Exceptions.TypeError, "value cannot be converted to Type");
                }

                return(false);
            }

            return(ToPrimitive(value, obType, out result, setError));
        }