ToManaged() static private méthode

static private ToManaged ( IntPtr value, Type type, object &result, bool setError ) : bool
value System.IntPtr
type System.Type
result object
setError bool
Résultat bool
Exemple #1
0
        static bool TryConvertArgument(IntPtr op, Type parameterType, bool needsResolution,
                                       out object arg, out bool isOut)
        {
            arg   = null;
            isOut = false;
            var clrtype = TryComputeClrArgumentType(parameterType, op, needsResolution: needsResolution);

            if (clrtype == null)
            {
                return(false);
            }

            if (!Converter.ToManaged(op, clrtype, out arg, false))
            {
                // Arturo Rodriguez -- Start
                // Needed to allow Python objects to be passed from python code to CLR functions.
                var pyobj = new PyObject(op);
                var ptype = pyobj.GetPythonType();

                arg     = pyobj;
                clrtype = arg.GetType();
                isOut   = clrtype.IsByRef;
                return(true);
                // Arturo Rodriguez -- End

                // Repo code
                // Exceptions.Clear();
                // return false;
            }

            isOut = clrtype.IsByRef;
            return(true);
        }
        /// <summary>
        /// Descriptor __set__ implementation. This method sets the value of
        /// a field based on the given Python value. The Python value must be
        /// convertible to the type of the field.
        /// </summary>
        public new static int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val)
        {
            var    self = (FieldObject)GetManagedObject(ds);
            object newval;

            if (self == null)
            {
                return(-1);
            }

            if (val == IntPtr.Zero)
            {
                Exceptions.SetError(Exceptions.TypeError, "cannot delete field");
                return(-1);
            }

            FieldInfo info = self.info;

            if (info.IsLiteral || info.IsInitOnly)
            {
                Exceptions.SetError(Exceptions.TypeError, "field is read-only");
                return(-1);
            }

            bool is_static = info.IsStatic;

            if (ob == IntPtr.Zero || ob == Runtime.PyNone)
            {
                if (!is_static)
                {
                    Exceptions.SetError(Exceptions.TypeError, "instance attribute must be set through a class instance");
                    return(-1);
                }
            }

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

            try
            {
                if (!is_static)
                {
                    var co = (CLRObject)GetManagedObject(ob);
                    info.SetValue(co.inst, newval);
                }
                else
                {
                    info.SetValue(null, newval);
                }
                return(0);
            }
            catch (Exception e)
            {
                Exceptions.SetError(Exceptions.TypeError, e.Message);
                return(-1);
            }
        }
Exemple #3
0
        /// <summary>
        /// Implements __new__ for reflected classes and value types.
        /// </summary>
        public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw)
        {
            var self = GetManagedObject(tp) as ClassObject;

            // Sanity check: this ensures a graceful error if someone does
            // something intentially wrong like use the managed metatype for
            // a class that is not really derived from a managed class.
            if (self == null)
            {
                return(Exceptions.RaiseTypeError("invalid object"));
            }

            Type type = self.type;

            // Primitive types do not have constructors, but they look like
            // they do from Python. If the ClassObject represents one of the
            // convertible primitive types, just convert the arg directly.
            if (type.IsPrimitive || type == typeof(string))
            {
                if (Runtime.PyTuple_Size(args) != 1)
                {
                    Exceptions.SetError(Exceptions.TypeError, "no constructors match given arguments");
                    return(IntPtr.Zero);
                }

                IntPtr op = Runtime.PyTuple_GetItem(args, 0);
                object result;

                if (!Converter.ToManaged(op, type, out result, true))
                {
                    return(IntPtr.Zero);
                }

                return(CLRObject.GetInstHandle(result, tp));
            }

            if (type.IsAbstract)
            {
                Exceptions.SetError(Exceptions.TypeError, "cannot instantiate abstract class");
                return(IntPtr.Zero);
            }

            if (type.IsEnum)
            {
                Exceptions.SetError(Exceptions.TypeError, "cannot instantiate enumeration");
                return(IntPtr.Zero);
            }

            object obj = self.binder.InvokeRaw(IntPtr.Zero, args, kw);

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

            return(CLRObject.GetInstHandle(obj, tp));
        }
Exemple #4
0
        public static IntPtr tp_new(IntPtr tpRaw, IntPtr args, IntPtr kw)
        {
            if (kw != IntPtr.Zero)
            {
                return(Exceptions.RaiseTypeError("array constructor takes no keyword arguments"));
            }

            var tp = new BorrowedReference(tpRaw);

            var self = GetManagedObject(tp) as ArrayObject;

            if (!self.type.Valid)
            {
                return(Exceptions.RaiseTypeError(self.type.DeletedMessage));
            }
            Type arrType = self.type.Value;

            long[] dimensions = new long[Runtime.PyTuple_Size(args)];
            if (dimensions.Length == 0)
            {
                return(Exceptions.RaiseTypeError("array constructor requires at least one integer argument or an object convertible to array"));
            }
            if (dimensions.Length != 1)
            {
                return(CreateMultidimensional(arrType.GetElementType(), dimensions,
                                              shapeTuple: new BorrowedReference(args),
                                              pyType: tp)
                       .DangerousMoveToPointerOrNull());
            }

            IntPtr op = Runtime.PyTuple_GetItem(args, 0);

            // create single dimensional array
            if (Runtime.PyInt_Check(op))
            {
                dimensions[0] = Runtime.PyLong_AsSignedSize_t(op);
                if (dimensions[0] == -1 && Exceptions.ErrorOccurred())
                {
                    Exceptions.Clear();
                }
                else
                {
                    return(NewInstance(arrType.GetElementType(), tp, dimensions)
                           .DangerousMoveToPointerOrNull());
                }
            }
            object result;

            // this implements casting to Array[T]
            if (!Converter.ToManaged(op, arrType, out result, true))
            {
                return(IntPtr.Zero);
            }
            return(CLRObject.GetInstHandle(result, tp)
                   .DangerousGetAddress());
        }
Exemple #5
0
        /// <summary>
        /// AsManagedObject Method
        /// </summary>
        /// <remarks>
        /// Return a managed object of the given type, based on the
        /// value of the Python object.
        /// </remarks>
        public object AsManagedObject(Type t)
        {
            object result;

            if (!Converter.ToManaged(obj, t, out result, false))
            {
                throw new InvalidCastException("cannot convert object to target type");
            }
            return(result);
        }
Exemple #6
0
        /// <summary>
        /// Helper function for ToArray and ToList that creates a IList out of iterable objects
        /// </summary>
        /// <param name="value"></param>
        /// <param name="IterObject"></param>
        /// <param name="obType"></param>
        /// <param name="elementType"></param>
        /// <param name="setError"></param>
        /// <returns></returns>
        private static IList MakeList(IntPtr value, IntPtr IterObject, Type obType, Type elementType, bool setError)
        {
            IList list;

            try
            {
                // MakeGenericType can throw because elementType may not be a valid generic argument even though elementType[] is a valid array type.
                // For example, if elementType is a pointer type.
                // See https://docs.microsoft.com/en-us/dotnet/api/system.type.makegenerictype#System_Type_MakeGenericType_System_Type
                var  constructedListType = typeof(List <>).MakeGenericType(elementType);
                bool IsSeqObj            = Runtime.PySequence_Check(value);
                if (IsSeqObj)
                {
                    var len = Runtime.PySequence_Size(value);
                    list = (IList)Activator.CreateInstance(constructedListType, new Object[] { (int)len });
                }
                else
                {
                    // CreateInstance can throw even if MakeGenericType succeeded.
                    // See https://docs.microsoft.com/en-us/dotnet/api/system.activator.createinstance#System_Activator_CreateInstance_System_Type_
                    list = (IList)Activator.CreateInstance(constructedListType);
                }
            }
            catch (Exception e)
            {
                if (setError)
                {
                    Exceptions.SetError(e);
                    SetConversionError(value, obType);
                }

                return(null);
            }

            IntPtr item;
            var    usedImplicit = false;

            while ((item = Runtime.PyIter_Next(IterObject)) != IntPtr.Zero)
            {
                object obj;

                if (!Converter.ToManaged(item, elementType, out obj, setError, out usedImplicit))
                {
                    Runtime.XDecref(item);
                    return(null);
                }

                list.Add(obj);
                Runtime.XDecref(item);
            }
            Runtime.XDecref(IterObject);

            return(list);
        }
Exemple #7
0
        private static NewReference NewEnum(Type type, BorrowedReference args, BorrowedReference tp)
        {
            nint argCount       = Runtime.PyTuple_Size(args);
            bool allowUnchecked = false;

            if (argCount == 2)
            {
                var allow = Runtime.PyTuple_GetItem(args, 1);
                if (!Converter.ToManaged(allow, typeof(bool), out var allowObj, true) || allowObj is null)
                {
                    Exceptions.RaiseTypeError("second argument to enum constructor must be a boolean");
                    return(default);
Exemple #8
0
        public static NewReference tp_new(BorrowedReference tp, BorrowedReference args, BorrowedReference kw)
        {
            if (kw != null)
            {
                return(Exceptions.RaiseTypeError("array constructor takes no keyword arguments"));
            }

            var self = (ArrayObject)GetManagedObject(tp) !;

            if (!self.type.Valid)
            {
                return(Exceptions.RaiseTypeError(self.type.DeletedMessage));
            }
            Type arrType = self.type.Value;

            long[] dimensions = new long[Runtime.PyTuple_Size(args)];
            if (dimensions.Length == 0)
            {
                return(Exceptions.RaiseTypeError("array constructor requires at least one integer argument or an object convertible to array"));
            }
            if (dimensions.Length != 1)
            {
                return(CreateMultidimensional(arrType.GetElementType(), dimensions,
                                              shapeTuple: args,
                                              pyType: tp));
            }

            BorrowedReference op = Runtime.PyTuple_GetItem(args, 0);

            // create single dimensional array
            if (Runtime.PyInt_Check(op))
            {
                dimensions[0] = Runtime.PyLong_AsSignedSize_t(op);
                if (dimensions[0] == -1 && Exceptions.ErrorOccurred())
                {
                    Exceptions.Clear();
                }
                else
                {
                    return(NewInstance(arrType.GetElementType(), tp, dimensions));
                }
            }

            // this implements casting to Array[T]
            if (Converter.ToManaged(op, arrType, out object?result, true))
            {
                return(CLRObject.GetReference(result !, tp));
            }
            else
            {
                return(default);
Exemple #9
0
        /// <summary>
        /// As Method
        /// </summary>
        /// <remarks>
        /// Return a managed object of the given type, based on the
        /// value of the Python object.
        /// </remarks>
        public T As <T>()
        {
            if (typeof(T) == typeof(PyObject) || typeof(T) == typeof(object))
            {
                return((T)(this as object));
            }
            object result;

            if (!Converter.ToManaged(obj, typeof(T), out result, false))
            {
                throw new InvalidCastException("cannot convert object to target type");
            }
            return((T)result);
        }
        /// <summary>
        /// Convert a Python value to a correctly typed managed array instance.
        /// The Python value must support the Python iterator protocol or and the
        /// items in the sequence must be convertible to the target array type.
        /// </summary>
        private static bool ToArray(IntPtr value, Type obType, out object result, bool setError)
        {
            Type elementType = obType.GetElementType();

            result = null;

            bool IsSeqObj = Runtime.PySequence_Check(value);
            var  len      = IsSeqObj ? Runtime.PySequence_Size(value) : -1;

            IntPtr IterObject = Runtime.PyObject_GetIter(value);

            if (IterObject == IntPtr.Zero)
            {
                if (setError)
                {
                    SetConversionError(value, obType);
                }
                return(false);
            }

            Array items;

            var   listType            = typeof(List <>);
            var   constructedListType = listType.MakeGenericType(elementType);
            IList list = IsSeqObj ? (IList)Activator.CreateInstance(constructedListType, new Object[] { (int)len }) :
                         (IList)Activator.CreateInstance(constructedListType);
            IntPtr item;

            while ((item = Runtime.PyIter_Next(IterObject)) != IntPtr.Zero)
            {
                object obj = null;

                if (!Converter.ToManaged(item, elementType, out obj, true))
                {
                    Runtime.XDecref(item);
                    return(false);
                }

                list.Add(obj);
                Runtime.XDecref(item);
            }
            Runtime.XDecref(IterObject);

            items = Array.CreateInstance(elementType, list.Count);
            list.CopyTo(items, 0);

            result = items;
            return(true);
        }
Exemple #11
0
        //====================================================================
        // Convert a Python value to a correctly typed managed array instance.
        // The Python value must support the Python sequence protocol and the
        // items in the sequence must be convertible to the target array type.
        //====================================================================

        static bool ToArray(IntPtr value, Type obType, out Object result,
                            bool setError)
        {
            Type elementType = obType.GetElementType();
            int  size        = Runtime.PySequence_Size(value);

            result = null;

            if (size < 0)
            {
                if (setError)
                {
                    SetConversionError(value, obType);
                }
                return(false);
            }

            Array items = Array.CreateInstance(elementType, size);

            // XXX - is there a better way to unwrap this if it is a real
            // array?
            for (int i = 0; i < size; i++)
            {
                Object obj  = null;
                IntPtr item = Runtime.PySequence_GetItem(value, i);
                if (item == IntPtr.Zero)
                {
                    if (setError)
                    {
                        SetConversionError(value, obType);
                        return(false);
                    }
                }

                if (!Converter.ToManaged(item, elementType, out obj, true))
                {
                    Runtime.Decref(item);
                    return(false);
                }

                items.SetValue(obj, i);
                Runtime.Decref(item);
            }

            result = items;
            return(true);
        }
Exemple #12
0
        public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw)
        {
            var self = GetManagedObject(tp) as ArrayObject;

            if (Runtime.Interop.PyTuple_Size(args) != 1)
            {
                return(Exceptions.RaiseTypeError("array expects 1 argument"));
            }
            IntPtr op = Runtime.Interop.PyTuple_GetItem(args, 0);
            object result;

            if (!Converter.ToManaged(op, self.type, out result, true))
            {
                return(IntPtr.Zero);
            }
            return(CLRObject.GetInstHandle(result, tp));
        }
Exemple #13
0
        public object TrueDispatch(ArrayList args)
        {
            MethodInfo method = dtype.GetMethod("Invoke");

            ParameterInfo[] pi     = method.GetParameters();
            IntPtr          pyargs = Runtime.PyTuple_New(pi.Length);
            Type            rtype  = method.ReturnType;

            for (int i = 0; i < pi.Length; i++)
            {
                // Here we own the reference to the Python value, and we
                // give the ownership to the arg tuple.
                IntPtr arg = Converter.ToPython(args[i], pi[i].ParameterType);
                Runtime.PyTuple_SetItem(pyargs, i, arg);
            }

            IntPtr op = Runtime.PyObject_Call(target, pyargs, IntPtr.Zero);

            Runtime.Decref(pyargs);

            if (op == IntPtr.Zero)
            {
                PythonException e = new PythonException();
                throw e;
            }

            if (rtype == typeof(void))
            {
                return(null);
            }

            Object result = null;

            if (!Converter.ToManaged(op, rtype, out result, false))
            {
                string s = "could not convert Python result to " +
                           rtype.ToString();
                Runtime.Decref(op);
                throw new ConversionException(s);
            }

            Runtime.Decref(op);
            return(result);
        }
Exemple #14
0
        /// <summary>
        /// Implements __contains__ for dictionary types.
        /// </summary>
        public static int sq_contains(BorrowedReference ob, BorrowedReference v)
        {
            var obj  = (CLRObject)GetManagedObject(ob);
            var self = obj.inst;

            var key        = Tuple.Create(self.GetType(), "ContainsKey");
            var methodInfo = methodsByType[key];

            var    parameters = methodInfo.GetParameters();
            object arg;

            if (!Converter.ToManaged(v, parameters[0].ParameterType, out arg, false))
            {
                Exceptions.SetError(Exceptions.TypeError,
                                    $"invalid parameter type for sq_contains: should be {Converter.GetTypeByAlias(v)}, found {parameters[0].ParameterType}");
            }

            return((bool)methodInfo.Invoke(self, new[] { arg }) ? 1 : 0);
        }
Exemple #15
0
        /// <summary>
        /// Implements __contains__ for array types.
        /// </summary>
        public static int sq_contains(IntPtr ob, IntPtr v)
        {
            var    obj      = (CLRObject)GetManagedObject(ob);
            Type   itemType = obj.inst.GetType().GetElementType();
            var    items    = obj.inst as IList;
            object value;

            if (!Converter.ToManaged(v, itemType, out value, false))
            {
                return(0);
            }

            if (items.Contains(value))
            {
                return(1);
            }

            return(0);
        }
        /// <summary>
        /// Try to convert a Python argument object to a managed CLR type.
        /// If unsuccessful, may set a Python error.
        /// </summary>
        /// <param name="op">Pointer to the Python argument object.</param>
        /// <param name="parameterType">That parameter's managed type.</param>
        /// <param name="arg">Converted argument.</param>
        /// <param name="isOut">Whether the CLR type is passed by reference.</param>
        /// <returns>true on success</returns>
        static bool TryConvertArgument(IntPtr op, Type parameterType,
                                       out object arg, out bool isOut)
        {
            arg   = null;
            isOut = false;
            var clrtype = TryComputeClrArgumentType(parameterType, op);

            if (clrtype == null)
            {
                return(false);
            }

            if (!Converter.ToManaged(op, clrtype, out arg, true))
            {
                return(false);
            }

            isOut = clrtype.IsByRef;
            return(true);
        }
Exemple #17
0
        /// <summary>
        /// Helper method that will enumerate a Python sequence convert its values to the given
        /// type and send them to the provided action
        /// </summary>
        private static bool ApplyActionToPySequence(IntPtr value,
                                                    Type obType,
                                                    bool setError,
                                                    int size,
                                                    Type elementType,
                                                    Action <object> action)
        {
            if (size < 0)
            {
                if (setError)
                {
                    SetConversionError(value, obType);
                }
                return(false);
            }

            for (var i = 0; i < size; i++)
            {
                object obj  = null;
                IntPtr item = Runtime.PySequence_GetItem(value, i);
                if (item == IntPtr.Zero)
                {
                    if (setError)
                    {
                        SetConversionError(value, obType);
                        return(false);
                    }
                }

                if (!Converter.ToManaged(item, elementType, out obj, true))
                {
                    Runtime.XDecref(item);
                    return(false);
                }

                action(obj);
                Runtime.XDecref(item);
            }

            return(true);
        }
        static bool TryConvertArgument(IntPtr op, Type parameterType, bool needsResolution,
                                       out object arg, out bool isOut)
        {
            arg   = null;
            isOut = false;
            var clrtype = TryComputeClrArgumentType(parameterType, op, needsResolution: needsResolution);

            if (clrtype == null)
            {
                return(false);
            }

            if (!Converter.ToManaged(op, clrtype, out arg, false))
            {
                Exceptions.Clear();
                return(false);
            }

            isOut = clrtype.IsByRef;
            return(true);
        }
        //====================================================================
        // Implements __new__ for reflected classes and value types.
        //====================================================================

        public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw)
        {
            ClassObject self = GetManagedObject(tp) as ClassObject;

            // Sanity check: this ensures a graceful error if someone does
            // something intentially wrong like use the managed metatype for
            // a class that is not really derived from a managed class.

            if (self == null)
            {
                return(Exceptions.RaiseTypeError("invalid object"));
            }

            Type type = self.type;

            // Primitive types do not have constructors, but they look like
            // they do from Python. If the ClassObject represents one of the
            // convertible primitive types, just convert the arg directly.

            if (type.IsPrimitive || type == typeof(String))
            {
                if (Runtime.PyTuple_Size(args) != 1)
                {
                    Exceptions.SetError(Exceptions.TypeError,
                                        "no constructors match given arguments"
                                        );
                    return(IntPtr.Zero);
                }

                IntPtr op = Runtime.PyTuple_GetItem(args, 0);
                Object result;

                if (!Converter.ToManaged(op, type, out result, true))
                {
                    return(IntPtr.Zero);
                }

                return(CLRObject.GetInstHandle(result, tp));
            }

            if (type.IsAbstract)
            {
                Exceptions.SetError(Exceptions.TypeError,
                                    "cannot instantiate abstract class"
                                    );
                return(IntPtr.Zero);
            }

            if (type.IsEnum)
            {
                Exceptions.SetError(Exceptions.TypeError,
                                    "cannot instantiate enumeration"
                                    );
                return(IntPtr.Zero);
            }

            Object obj = self.binder.InvokeRaw(IntPtr.Zero, args, kw);

            if (obj == null)
            {
                // It is possible for __new__ to be invoked on construction
                // of a Python subclass of a managed class, so args may
                // reflect more args than are required to instantiate the
                // class. So if we cant find a ctor that matches, we'll see
                // if there is a default constructor and, if so, assume that
                // any extra args are intended for the subclass' __init__.

                IntPtr eargs = Runtime.PyTuple_New(0);
                obj = self.binder.InvokeRaw(IntPtr.Zero, eargs, kw);
                Runtime.Decref(eargs);
                if (obj == null)
                {
                    return(IntPtr.Zero);
                }
            }

            return(CLRObject.GetInstHandle(obj, tp));
        }
Exemple #20
0
        internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw,
                              MethodBase info, MethodInfo[] methodinfo)
        {
            // loop to find match, return invoker w/ or /wo error
            MethodBase[] _methods = null;
            int          pynargs  = Runtime.PyTuple_Size(args);
            object       arg;
            bool         isGeneric = false;

            if (info != null)
            {
                _methods = (MethodBase[])Array.CreateInstance(
                    typeof(MethodBase), 1
                    );
                _methods.SetValue(info, 0);
            }
            else
            {
                _methods = GetMethods();
            }

            for (int i = 0; i < _methods.Length; i++)
            {
                MethodBase mi = _methods[i];
                if (mi.IsGenericMethod)
                {
                    isGeneric = true;
                }
                ParameterInfo[] pi         = mi.GetParameters();
                int             clrnargs   = pi.Length;
                bool            match      = false;
                int             arrayStart = -1;
                int             outs       = 0;

                if (pynargs == clrnargs)
                {
                    match = true;
                }
                else if ((pynargs > clrnargs) && (clrnargs > 0) &&
                         (pi[clrnargs - 1].ParameterType.IsArray))
                {
                    // The last argument of the mananged functions seems to
                    // accept multiple arguments as a array. Hopefully it's a
                    // spam(params object[] egg) style method
                    match      = true;
                    arrayStart = clrnargs - 1;
                }

                if (match)
                {
                    Object[] margs = new Object[clrnargs];

                    for (int n = 0; n < clrnargs; n++)
                    {
                        IntPtr op;
                        if (arrayStart == n)
                        {
                            // map remaining Python arguments to a tuple since
                            // the managed function accepts it - hopefully :]
                            op = Runtime.PyTuple_GetSlice(args, arrayStart, pynargs);
                        }
                        else
                        {
                            op = Runtime.PyTuple_GetItem(args, n);
                        }
                        Type type = pi[n].ParameterType;
                        if (pi[n].IsOut || type.IsByRef)
                        {
                            outs++;
                        }

                        if (!Converter.ToManaged(op, type, out arg, false))
                        {
                            Exceptions.Clear();
                            margs = null;
                            break;
                        }
                        if (arrayStart == n)
                        {
                            // GetSlice() creates a new reference but GetItem()
                            // returns only a borrow reference.
                            Runtime.Decref(op);
                        }
                        margs[n] = arg;
                    }

                    if (margs == null)
                    {
                        continue;
                    }

                    Object target = null;
                    if ((!mi.IsStatic) && (inst != IntPtr.Zero))
                    {
                        //CLRObject co = (CLRObject)ManagedType.GetManagedObject(inst);
                        // InvalidCastException: Unable to cast object of type
                        // 'Python.Runtime.ClassObject' to type 'Python.Runtime.CLRObject'
                        CLRObject co = ManagedType.GetManagedObject(inst) as CLRObject;

                        // Sanity check: this ensures a graceful exit if someone does
                        // something intentionally wrong like call a non-static method
                        // on the class rather than on an instance of the class.
                        // XXX maybe better to do this before all the other rigmarole.
                        if (co == null)
                        {
                            return(null);
                        }
                        target = co.inst;
                    }

                    return(new Binding(mi, target, margs, outs));
                }
            }
            // We weren't able to find a matching method but at least one
            // is a generic method and info is null. That happens when a generic
            // method was not called using the [] syntax. Let's introspect the
            // type of the arguments and use it to construct the correct method.
            if (isGeneric && (info == null) && (methodinfo != null))
            {
                Type[]     types = Runtime.PythonArgsToTypeArray(args, true);
                MethodInfo mi    = MethodBinder.MatchParameters(methodinfo, types);
                return(Bind(inst, args, kw, mi, null));
            }
            return(null);
        }
Exemple #21
0
        private object?TrueDispatch(object?[] args)
        {
            MethodInfo method = dtype.GetMethod("Invoke");

            ParameterInfo[] pi    = method.GetParameters();
            Type            rtype = method.ReturnType;

            NewReference callResult;

            using (var pyargs = Runtime.PyTuple_New(pi.Length))
            {
                for (var i = 0; i < pi.Length; i++)
                {
                    // Here we own the reference to the Python value, and we
                    // give the ownership to the arg tuple.
                    using var arg = Converter.ToPython(args[i], pi[i].ParameterType);
                    int res = Runtime.PyTuple_SetItem(pyargs.Borrow(), i, arg.StealOrThrow());
                    if (res != 0)
                    {
                        throw PythonException.ThrowLastAsClrException();
                    }
                }

                callResult = Runtime.PyObject_Call(target, pyargs.Borrow(), null);
            }

            if (callResult.IsNull())
            {
                throw PythonException.ThrowLastAsClrException();
            }

            using (callResult)
            {
                BorrowedReference op = callResult.Borrow();
                int byRefCount       = pi.Count(parameterInfo => parameterInfo.ParameterType.IsByRef);
                if (byRefCount > 0)
                {
                    // By symmetry with MethodBinder.Invoke, when there are out
                    // parameters we expect to receive a tuple containing
                    // the result, if any, followed by the out parameters. If there is only
                    // one out parameter and the return type of the method is void,
                    // we instead receive the out parameter as the result from Python.

                    bool isVoid    = rtype == typeof(void);
                    int  tupleSize = byRefCount + (isVoid ? 0 : 1);
                    if (isVoid && byRefCount == 1)
                    {
                        // The return type is void and there is a single out parameter.
                        for (int i = 0; i < pi.Length; i++)
                        {
                            Type t = pi[i].ParameterType;
                            if (t.IsByRef)
                            {
                                if (!Converter.ToManaged(op, t, out args[i], true))
                                {
                                    Exceptions.RaiseTypeError($"The Python function did not return {t.GetElementType()} (the out parameter type)");
                                    throw PythonException.ThrowLastAsClrException();
                                }
                                break;
                            }
                        }
                        return(null);
                    }
                    else if (Runtime.PyTuple_Check(op) && Runtime.PyTuple_Size(op) == tupleSize)
                    {
                        int index = isVoid ? 0 : 1;
                        for (int i = 0; i < pi.Length; i++)
                        {
                            Type t = pi[i].ParameterType;
                            if (t.IsByRef)
                            {
                                BorrowedReference item = Runtime.PyTuple_GetItem(op, index++);
                                if (!Converter.ToManaged(item, t, out args[i], true))
                                {
                                    Exceptions.RaiseTypeError($"The Python function returned a tuple where element {i} was not {t.GetElementType()} (the out parameter type)");
                                    throw PythonException.ThrowLastAsClrException();
                                }
                            }
                        }
                        if (isVoid)
                        {
                            return(null);
                        }
                        BorrowedReference item0 = Runtime.PyTuple_GetItem(op, 0);
                        if (!Converter.ToManaged(item0, rtype, out object?result0, true))
                        {
                            Exceptions.RaiseTypeError($"The Python function returned a tuple where element 0 was not {rtype} (the return type)");
                            throw PythonException.ThrowLastAsClrException();
                        }
                        return(result0);
                    }
                    else
                    {
                        string tpName = Runtime.PyObject_GetTypeName(op);
                        if (Runtime.PyTuple_Check(op))
                        {
                            tpName += $" of size {Runtime.PyTuple_Size(op)}";
                        }
                        StringBuilder sb = new StringBuilder();
                        if (!isVoid)
                        {
                            sb.Append(rtype.FullName);
                        }
                        for (int i = 0; i < pi.Length; i++)
                        {
                            Type t = pi[i].ParameterType;
                            if (t.IsByRef)
                            {
                                if (sb.Length > 0)
                                {
                                    sb.Append(",");
                                }
                                sb.Append(t.GetElementType().FullName);
                            }
                        }
                        string returnValueString = isVoid ? "" : "the return value and ";
                        Exceptions.RaiseTypeError($"Expected a tuple ({sb}) of {returnValueString}the values for out and ref parameters, got {tpName}.");
                        throw PythonException.ThrowLastAsClrException();
                    }
                }

                if (rtype == typeof(void))
                {
                    return(null);
                }

                if (!Converter.ToManaged(op, rtype, out object?result, true))
                {
                    throw PythonException.ThrowLastAsClrException();
                }

                return(result);
            }
        }
Exemple #22
0
        /// <summary>
        /// Convert a Python value to a correctly typed managed array instance.
        /// The Python value must support the Python iterator protocol or and the
        /// items in the sequence must be convertible to the target array type.
        /// </summary>
        private static bool ToArray(BorrowedReference value, Type obType, out object?result, bool setError)
        {
            Type elementType = obType.GetElementType();

            result = null;

            using var IterObject = Runtime.PyObject_GetIter(value);
            if (IterObject.IsNull())
            {
                if (setError)
                {
                    SetConversionError(value, obType);
                }
                else
                {
                    // PyObject_GetIter will have set an error
                    Exceptions.Clear();
                }
                return(false);
            }

            IList list;

            try
            {
                // MakeGenericType can throw because elementType may not be a valid generic argument even though elementType[] is a valid array type.
                // For example, if elementType is a pointer type.
                // See https://docs.microsoft.com/en-us/dotnet/api/system.type.makegenerictype#System_Type_MakeGenericType_System_Type
                var      constructedListType = typeof(List <>).MakeGenericType(elementType);
                bool     IsSeqObj            = Runtime.PySequence_Check(value);
                object[] constructorArgs     = Array.Empty <object>();
                if (IsSeqObj)
                {
                    var len = Runtime.PySequence_Size(value);
                    if (len >= 0)
                    {
                        if (len <= int.MaxValue)
                        {
                            constructorArgs = new object[] { (int)len };
                        }
                    }
                    else
                    {
                        // for the sequences, that explicitly deny calling __len__()
                        Exceptions.Clear();
                    }
                }
                // CreateInstance can throw even if MakeGenericType succeeded.
                // See https://docs.microsoft.com/en-us/dotnet/api/system.activator.createinstance#System_Activator_CreateInstance_System_Type_
                list = (IList)Activator.CreateInstance(constructedListType, args: constructorArgs);
            }
            catch (Exception e)
            {
                if (setError)
                {
                    Exceptions.SetError(e);
                    SetConversionError(value, obType);
                }
                return(false);
            }

            while (true)
            {
                using var item = Runtime.PyIter_Next(IterObject.Borrow());
                if (item.IsNull())
                {
                    break;
                }

                if (!Converter.ToManaged(item.Borrow(), elementType, out var obj, setError))
                {
                    return(false);
                }

                list.Add(obj);
            }

            if (Exceptions.ErrorOccurred())
            {
                if (!setError)
                {
                    Exceptions.Clear();
                }
                return(false);
            }

            Array items = Array.CreateInstance(elementType, list.Count);

            list.CopyTo(items, 0);

            result = items;
            return(true);
        }
Exemple #23
0
        internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, MethodInfo[] methodinfo)
        {
            // Relevant function variables used post conversion
            var     isGeneric = false;
            Binding bindingUsingImplicitConversion = null;

            // If we have KWArgs create dictionary and collect them
            Dictionary <string, IntPtr> kwArgDict = null;

            if (kw != IntPtr.Zero)
            {
                var pyKwArgsCount = (int)Runtime.PyDict_Size(kw);
                kwArgDict = new Dictionary <string, IntPtr>(pyKwArgsCount);
                IntPtr keylist   = Runtime.PyDict_Keys(kw);
                IntPtr valueList = Runtime.PyDict_Values(kw);
                for (int i = 0; i < pyKwArgsCount; ++i)
                {
                    var keyStr = Runtime.GetManagedString(Runtime.PyList_GetItem(new BorrowedReference(keylist), i));
                    kwArgDict[keyStr] = Runtime.PyList_GetItem(new BorrowedReference(valueList), i).DangerousGetAddress();
                }
                Runtime.XDecref(keylist);
                Runtime.XDecref(valueList);
            }

            // Fetch our methods we are going to attempt to match and bind too.
            var methods = info == null?GetMethods()
                              : new List <MethodInformation>(1)
            {
                new MethodInformation(info, info.GetParameters())
            };

            foreach (var methodInformation in methods)
            {
                // Relevant method variables
                var mi = methodInformation.MethodBase;
                var pi = methodInformation.ParameterInfo;

                isGeneric = mi.IsGenericMethod;
                int pyArgCount = (int)Runtime.PyTuple_Size(args);


                // Special case for operators
                bool isOperator = OperatorMethod.IsOperatorMethod(mi);
                // Binary operator methods will have 2 CLR args but only one Python arg
                // (unary operators will have 1 less each), since Python operator methods are bound.
                isOperator = isOperator && pyArgCount == pi.Length - 1;
                bool isReverse = isOperator && OperatorMethod.IsReverse((MethodInfo)mi);  // Only cast if isOperator.
                if (isReverse && OperatorMethod.IsComparisonOp((MethodInfo)mi))
                {
                    continue;  // Comparison operators in Python have no reverse mode.
                }
                // Preprocessing pi to remove either the first or second argument.
                if (isOperator && !isReverse)
                {
                    // The first Python arg is the right operand, while the bound instance is the left.
                    // We need to skip the first (left operand) CLR argument.
                    pi = pi.Skip(1).ToArray();
                }
                else if (isOperator && isReverse)
                {
                    // The first Python arg is the left operand.
                    // We need to take the first CLR argument.
                    pi = pi.Take(1).ToArray();
                }

                // Must be done after IsOperator section
                int clrArgCount = pi.Length;

                if (CheckMethodArgumentsMatch(clrArgCount,
                                              pyArgCount,
                                              kwArgDict,
                                              pi,
                                              out bool paramsArray,
                                              out ArrayList defaultArgList))
                {
                    var outs  = 0;
                    var margs = new object[clrArgCount];

                    int paramsArrayIndex       = paramsArray ? pi.Length - 1 : -1; // -1 indicates no paramsArray
                    var usedImplicitConversion = false;

                    // Conversion loop for each parameter
                    for (int paramIndex = 0; paramIndex < clrArgCount; paramIndex++)
                    {
                        IntPtr op        = IntPtr.Zero;     // Python object to be converted; not yet set
                        var    parameter = pi[paramIndex];  // Clr parameter we are targeting
                        object arg;                         // Python -> Clr argument

                        // Check our KWargs for this parameter
                        bool hasNamedParam  = kwArgDict == null ? false : kwArgDict.TryGetValue(parameter.Name, out op);
                        bool isNewReference = false;

                        // Check if we are going to use default
                        if (paramIndex >= pyArgCount && !(hasNamedParam || (paramsArray && paramIndex == paramsArrayIndex)))
                        {
                            if (defaultArgList != null)
                            {
                                margs[paramIndex] = defaultArgList[paramIndex - pyArgCount];
                            }

                            continue;
                        }

                        // At this point, if op is IntPtr.Zero we don't have a KWArg and are not using default
                        if (op == IntPtr.Zero)
                        {
                            // If we have reached the paramIndex
                            if (paramsArrayIndex == paramIndex)
                            {
                                op = HandleParamsArray(args, paramsArrayIndex, pyArgCount, out isNewReference);
                            }
                            else
                            {
                                op = Runtime.PyTuple_GetItem(args, paramIndex);
                            }
                        }

                        // this logic below handles cases when multiple overloading methods
                        // are ambiguous, hence comparison between Python and CLR types
                        // is necessary
                        Type   clrtype = null;
                        IntPtr pyoptype;
                        if (methods.Count > 1)
                        {
                            pyoptype = IntPtr.Zero;
                            pyoptype = Runtime.PyObject_Type(op);
                            Exceptions.Clear();
                            if (pyoptype != IntPtr.Zero)
                            {
                                clrtype = Converter.GetTypeByAlias(pyoptype);
                            }
                            Runtime.XDecref(pyoptype);
                        }


                        if (clrtype != null)
                        {
                            var typematch = false;

                            if ((parameter.ParameterType != typeof(object)) && (parameter.ParameterType != clrtype))
                            {
                                IntPtr pytype = Converter.GetPythonTypeByAlias(parameter.ParameterType);
                                pyoptype = Runtime.PyObject_Type(op);
                                Exceptions.Clear();
                                if (pyoptype != IntPtr.Zero)
                                {
                                    if (pytype != pyoptype)
                                    {
                                        typematch = false;
                                    }
                                    else
                                    {
                                        typematch = true;
                                        clrtype   = parameter.ParameterType;
                                    }
                                }
                                if (!typematch)
                                {
                                    // this takes care of nullables
                                    var underlyingType = Nullable.GetUnderlyingType(parameter.ParameterType);
                                    if (underlyingType == null)
                                    {
                                        underlyingType = parameter.ParameterType;
                                    }
                                    // this takes care of enum values
                                    TypeCode argtypecode   = Type.GetTypeCode(underlyingType);
                                    TypeCode paramtypecode = Type.GetTypeCode(clrtype);
                                    if (argtypecode == paramtypecode)
                                    {
                                        typematch = true;
                                        clrtype   = parameter.ParameterType;
                                    }
                                    // accepts non-decimal numbers in decimal parameters
                                    if (underlyingType == typeof(decimal))
                                    {
                                        clrtype   = parameter.ParameterType;
                                        typematch = Converter.ToManaged(op, clrtype, out arg, false);
                                    }
                                    // this takes care of implicit conversions
                                    var opImplicit = parameter.ParameterType.GetMethod("op_Implicit", new[] { clrtype });
                                    if (opImplicit != null)
                                    {
                                        usedImplicitConversion = typematch = opImplicit.ReturnType == parameter.ParameterType;
                                        clrtype = parameter.ParameterType;
                                    }
                                }
                                Runtime.XDecref(pyoptype);
                                if (!typematch)
                                {
                                    margs = null;
                                    break;
                                }
                            }
                            else
                            {
                                clrtype = parameter.ParameterType;
                            }
                        }
                        else
                        {
                            clrtype = parameter.ParameterType;
                        }

                        if (parameter.IsOut || clrtype.IsByRef)
                        {
                            outs++;
                        }

                        if (!Converter.ToManaged(op, clrtype, out arg, false))
                        {
                            Exceptions.Clear();
                            margs = null;
                            break;
                        }

                        if (isNewReference)
                        {
                            // TODO: is this a bug? Should this happen even if the conversion fails?
                            // GetSlice() creates a new reference but GetItem()
                            // returns only a borrow reference.
                            Runtime.XDecref(op);
                        }

                        margs[paramIndex] = arg;
                    }

                    if (margs == null)
                    {
                        continue;
                    }

                    if (isOperator)
                    {
                        if (inst != IntPtr.Zero)
                        {
                            if (ManagedType.GetManagedObject(inst) is CLRObject co)
                            {
                                bool isUnary = pyArgCount == 0;
                                // Postprocessing to extend margs.
                                var margsTemp = isUnary ? new object[1] : new object[2];
                                // If reverse, the bound instance is the right operand.
                                int boundOperandIndex = isReverse ? 1 : 0;
                                // If reverse, the passed instance is the left operand.
                                int passedOperandIndex = isReverse ? 0 : 1;
                                margsTemp[boundOperandIndex] = co.inst;
                                if (!isUnary)
                                {
                                    margsTemp[passedOperandIndex] = margs[0];
                                }
                                margs = margsTemp;
                            }
                            else
                            {
                                continue;
                            }
                        }
                    }

                    object target = null;
                    if (!mi.IsStatic && inst != IntPtr.Zero)
                    {
                        //CLRObject co = (CLRObject)ManagedType.GetManagedObject(inst);
                        // InvalidCastException: Unable to cast object of type
                        // 'Python.Runtime.ClassObject' to type 'Python.Runtime.CLRObject'
                        var co = ManagedType.GetManagedObject(inst) as CLRObject;

                        // Sanity check: this ensures a graceful exit if someone does
                        // something intentionally wrong like call a non-static method
                        // on the class rather than on an instance of the class.
                        // XXX maybe better to do this before all the other rigmarole.
                        if (co == null)
                        {
                            return(null);
                        }
                        target = co.inst;
                    }

                    var binding = new Binding(mi, target, margs, outs);
                    if (usedImplicitConversion)
                    {
                        // lets just keep the first binding using implicit conversion
                        // this is to respect method order/precedence
                        if (bindingUsingImplicitConversion == null)
                        {
                            // in this case we will not return the binding yet in case there is a match
                            // which does not use implicit conversions, which will return directly
                            bindingUsingImplicitConversion = binding;
                        }
                    }
                    else
                    {
                        return(binding);
                    }
                }
            }

            // if we generated a binding using implicit conversion return it
            if (bindingUsingImplicitConversion != null)
            {
                return(bindingUsingImplicitConversion);
            }

            // We weren't able to find a matching method but at least one
            // is a generic method and info is null. That happens when a generic
            // method was not called using the [] syntax. Let's introspect the
            // type of the arguments and use it to construct the correct method.
            if (isGeneric && info == null && methodinfo != null)
            {
                Type[]     types = Runtime.PythonArgsToTypeArray(args, true);
                MethodInfo mi    = MatchParameters(methodinfo, types);
                return(Bind(inst, args, kw, mi, null));
            }
            return(null);
        }
Exemple #24
0
        internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, MethodInfo[] methodinfo)
        {
            // loop to find match, return invoker w/ or /wo error
            int       pynargs = Runtime.PyTuple_Size(args);
            object    arg;
            var       isGeneric = false;
            ArrayList defaultArgList;
            Type      clrtype;
            Binding   bindingUsingImplicitConversion = null;

            var methods = info == null?GetMethods()
                              : new List <MethodInformation>(1)
            {
                new MethodInformation(info, info.GetParameters())
            };

            // TODO: Clean up
            foreach (var methodInformation in methods)
            {
                var mi = methodInformation.MethodBase;
                var pi = methodInformation.ParameterInfo;

                if (mi.IsGenericMethod)
                {
                    isGeneric = true;
                }
                int clrnargs = pi.Length;
                int arrayStart;

                if (CheckMethodArgumentsMatch(clrnargs,
                                              pynargs,
                                              pi,
                                              out arrayStart,
                                              out defaultArgList))
                {
                    var outs  = 0;
                    var margs = new object[clrnargs];
                    var usedImplicitConversion = false;

                    for (var n = 0; n < clrnargs; n++)
                    {
                        IntPtr op;
                        if (n < pynargs)
                        {
                            if (arrayStart == n)
                            {
                                // map remaining Python arguments to a tuple since
                                // the managed function accepts it - hopefully :]
                                op = Runtime.PyTuple_GetSlice(args, arrayStart, pynargs);
                            }
                            else
                            {
                                op = Runtime.PyTuple_GetItem(args, n);
                            }

                            // this logic below handles cases when multiple overloading methods
                            // are ambiguous, hence comparison between Python and CLR types
                            // is necessary
                            clrtype = null;
                            IntPtr pyoptype;
                            if (methods.Count > 1)
                            {
                                pyoptype = IntPtr.Zero;
                                pyoptype = Runtime.PyObject_Type(op);
                                Exceptions.Clear();
                                if (pyoptype != IntPtr.Zero)
                                {
                                    clrtype = Converter.GetTypeByAlias(pyoptype);
                                }
                                Runtime.XDecref(pyoptype);
                            }


                            if (clrtype != null)
                            {
                                var typematch = false;
                                if ((pi[n].ParameterType != typeof(object)) && (pi[n].ParameterType != clrtype))
                                {
                                    IntPtr pytype = Converter.GetPythonTypeByAlias(pi[n].ParameterType);
                                    pyoptype = Runtime.PyObject_Type(op);
                                    Exceptions.Clear();
                                    if (pyoptype != IntPtr.Zero)
                                    {
                                        if (pytype != pyoptype)
                                        {
                                            typematch = false;
                                        }
                                        else
                                        {
                                            typematch = true;
                                            clrtype   = pi[n].ParameterType;
                                        }
                                    }
                                    if (!typematch)
                                    {
                                        // this takes care of nullables
                                        var underlyingType = Nullable.GetUnderlyingType(pi[n].ParameterType);
                                        if (underlyingType == null)
                                        {
                                            underlyingType = pi[n].ParameterType;
                                        }
                                        // this takes care of enum values
                                        TypeCode argtypecode   = Type.GetTypeCode(underlyingType);
                                        TypeCode paramtypecode = Type.GetTypeCode(clrtype);
                                        if (argtypecode == paramtypecode)
                                        {
                                            typematch = true;
                                            clrtype   = pi[n].ParameterType;
                                        }
                                        // accepts non-decimal numbers in decimal parameters
                                        if (underlyingType == typeof(decimal))
                                        {
                                            clrtype   = pi[n].ParameterType;
                                            typematch = Converter.ToManaged(op, clrtype, out arg, false);
                                        }
                                        // this takes care of implicit conversions
                                        var opImplicit = pi[n].ParameterType.GetMethod("op_Implicit", new[] { clrtype });
                                        if (opImplicit != null)
                                        {
                                            usedImplicitConversion = typematch = opImplicit.ReturnType == pi[n].ParameterType;
                                            clrtype = pi[n].ParameterType;
                                        }
                                    }
                                    Runtime.XDecref(pyoptype);
                                    if (!typematch)
                                    {
                                        margs = null;
                                        break;
                                    }
                                }
                                else
                                {
                                    typematch = true;
                                    clrtype   = pi[n].ParameterType;
                                }
                            }
                            else
                            {
                                clrtype = pi[n].ParameterType;
                            }

                            if (pi[n].IsOut || clrtype.IsByRef)
                            {
                                outs++;
                            }

                            if (!Converter.ToManaged(op, clrtype, out arg, false))
                            {
                                Exceptions.Clear();
                                margs = null;
                                break;
                            }
                            if (arrayStart == n)
                            {
                                // GetSlice() creates a new reference but GetItem()
                                // returns only a borrow reference.
                                Runtime.XDecref(op);
                            }
                            margs[n] = arg;
                        }
                        else
                        {
                            if (defaultArgList != null)
                            {
                                margs[n] = defaultArgList[n - pynargs];
                            }
                        }
                    }

                    if (margs == null)
                    {
                        continue;
                    }

                    object target = null;
                    if (!mi.IsStatic && inst != IntPtr.Zero)
                    {
                        //CLRObject co = (CLRObject)ManagedType.GetManagedObject(inst);
                        // InvalidCastException: Unable to cast object of type
                        // 'Python.Runtime.ClassObject' to type 'Python.Runtime.CLRObject'
                        var co = ManagedType.GetManagedObject(inst) as CLRObject;

                        // Sanity check: this ensures a graceful exit if someone does
                        // something intentionally wrong like call a non-static method
                        // on the class rather than on an instance of the class.
                        // XXX maybe better to do this before all the other rigmarole.
                        if (co == null)
                        {
                            return(null);
                        }
                        target = co.inst;
                    }

                    var binding = new Binding(mi, target, margs, outs);
                    if (usedImplicitConversion)
                    {
                        // lets just keep the first binding using implicit conversion
                        // this is to respect method order/precedence
                        if (bindingUsingImplicitConversion == null)
                        {
                            // in this case we will not return the binding yet in case there is a match
                            // which does not use implicit conversions, which will return directly
                            bindingUsingImplicitConversion = binding;
                        }
                    }
                    else
                    {
                        return(binding);
                    }
                }
            }

            // if we generated a binding using implicit conversion return it
            if (bindingUsingImplicitConversion != null)
            {
                return(bindingUsingImplicitConversion);
            }

            // We weren't able to find a matching method but at least one
            // is a generic method and info is null. That happens when a generic
            // method was not called using the [] syntax. Let's introspect the
            // type of the arguments and use it to construct the correct method.
            if (isGeneric && info == null && methodinfo != null)
            {
                Type[]     types = Runtime.PythonArgsToTypeArray(args, true);
                MethodInfo mi    = MatchParameters(methodinfo, types);
                return(Bind(inst, args, kw, mi, null));
            }
            return(null);
        }
        internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, MethodInfo[] methodinfo)
        {
            // loop to find match, return invoker w/ or /wo error
            MethodBase[] _methods = null;
            int          pynargs  = Runtime.PyTuple_Size(args);
            object       arg;
            var          isGeneric      = false;
            ArrayList    defaultArgList = null;

            if (info != null)
            {
                _methods = new MethodBase[1];
                _methods.SetValue(info, 0);
            }
            else
            {
                _methods = GetMethods();
            }
            Type clrtype;

            // TODO: Clean up
            foreach (MethodBase mi in _methods)
            {
                if (mi.IsGenericMethod)
                {
                    isGeneric = true;
                }
                ParameterInfo[] pi         = mi.GetParameters();
                int             clrnargs   = pi.Length;
                var             match      = false;
                int             arrayStart = -1;
                var             outs       = 0;

                if (pynargs == clrnargs)
                {
                    match = true;
                }
                else if (pynargs < clrnargs)
                {
                    match          = true;
                    defaultArgList = new ArrayList();
                    for (int v = pynargs; v < clrnargs; v++)
                    {
                        if (pi[v].DefaultValue == DBNull.Value)
                        {
                            match = false;
                        }
                        else
                        {
                            defaultArgList.Add(pi[v].DefaultValue);
                        }
                    }
                }
                else if (pynargs > clrnargs && clrnargs > 0 &&
                         Attribute.IsDefined(pi[clrnargs - 1], typeof(ParamArrayAttribute)))
                {
                    // This is a `foo(params object[] bar)` style method
                    match      = true;
                    arrayStart = clrnargs - 1;
                }

                if (match)
                {
                    var margs = new object[clrnargs];

                    for (var n = 0; n < clrnargs; n++)
                    {
                        IntPtr op;
                        if (n < pynargs)
                        {
                            if (arrayStart == n)
                            {
                                // map remaining Python arguments to a tuple since
                                // the managed function accepts it - hopefully :]
                                op = Runtime.PyTuple_GetSlice(args, arrayStart, pynargs);
                            }
                            else
                            {
                                op = Runtime.PyTuple_GetItem(args, n);
                            }

                            // this logic below handles cases when multiple overloading methods
                            // are ambiguous, hence comparison between Python and CLR types
                            // is necessary
                            clrtype = null;
                            IntPtr pyoptype;
                            if (_methods.Length > 1)
                            {
                                pyoptype = IntPtr.Zero;
                                pyoptype = Runtime.PyObject_Type(op);
                                Exceptions.Clear();
                                if (pyoptype != IntPtr.Zero)
                                {
                                    clrtype = Converter.GetTypeByAlias(pyoptype);
                                }
                                Runtime.XDecref(pyoptype);
                            }


                            if (clrtype != null)
                            {
                                var typematch = false;
                                if ((pi[n].ParameterType != typeof(object)) && (pi[n].ParameterType != clrtype))
                                {
                                    IntPtr pytype = Converter.GetPythonTypeByAlias(pi[n].ParameterType);
                                    pyoptype = Runtime.PyObject_Type(op);
                                    Exceptions.Clear();
                                    if (pyoptype != IntPtr.Zero)
                                    {
                                        if (pytype != pyoptype)
                                        {
                                            typematch = false;
                                        }
                                        else
                                        {
                                            typematch = true;
                                            clrtype   = pi[n].ParameterType;
                                        }
                                    }
                                    if (!typematch)
                                    {
                                        // this takes care of nullables
                                        var underlyingType = Nullable.GetUnderlyingType(pi[n].ParameterType);
                                        if (underlyingType == null)
                                        {
                                            underlyingType = pi[n].ParameterType;
                                        }
                                        // this takes care of enum values
                                        TypeCode argtypecode   = Type.GetTypeCode(underlyingType);
                                        TypeCode paramtypecode = Type.GetTypeCode(clrtype);
                                        if (argtypecode == paramtypecode)
                                        {
                                            typematch = true;
                                            clrtype   = pi[n].ParameterType;
                                        }
                                        // this takes care of implicit conversions
                                        var opImplicit = pi[n].ParameterType.GetMethod("op_Implicit", new[] { clrtype });
                                        if (opImplicit != null)
                                        {
                                            typematch = opImplicit.ReturnType == pi[n].ParameterType;
                                            clrtype   = pi[n].ParameterType;
                                        }
                                    }
                                    Runtime.XDecref(pyoptype);
                                    if (!typematch)
                                    {
                                        margs = null;
                                        break;
                                    }
                                }
                                else
                                {
                                    typematch = true;
                                    clrtype   = pi[n].ParameterType;
                                }
                            }
                            else
                            {
                                clrtype = pi[n].ParameterType;
                            }

                            if (pi[n].IsOut || clrtype.IsByRef)
                            {
                                outs++;
                            }

                            if (!Converter.ToManaged(op, clrtype, out arg, false))
                            {
                                Exceptions.Clear();
                                margs = null;
                                break;
                            }
                            if (arrayStart == n)
                            {
                                // GetSlice() creates a new reference but GetItem()
                                // returns only a borrow reference.
                                Runtime.XDecref(op);
                            }
                            margs[n] = arg;
                        }
                        else
                        {
                            if (defaultArgList != null)
                            {
                                margs[n] = defaultArgList[n - pynargs];
                            }
                        }
                    }

                    if (margs == null)
                    {
                        continue;
                    }

                    object target = null;
                    if (!mi.IsStatic && inst != IntPtr.Zero)
                    {
                        //CLRObject co = (CLRObject)ManagedType.GetManagedObject(inst);
                        // InvalidCastException: Unable to cast object of type
                        // 'Python.Runtime.ClassObject' to type 'Python.Runtime.CLRObject'
                        var co = ManagedType.GetManagedObject(inst) as CLRObject;

                        // Sanity check: this ensures a graceful exit if someone does
                        // something intentionally wrong like call a non-static method
                        // on the class rather than on an instance of the class.
                        // XXX maybe better to do this before all the other rigmarole.
                        if (co == null)
                        {
                            return(null);
                        }
                        target = co.inst;
                    }

                    return(new Binding(mi, target, margs, outs));
                }
            }
            // We weren't able to find a matching method but at least one
            // is a generic method and info is null. That happens when a generic
            // method was not called using the [] syntax. Let's introspect the
            // type of the arguments and use it to construct the correct method.
            if (isGeneric && info == null && methodinfo != null)
            {
                Type[]     types = Runtime.PythonArgsToTypeArray(args, true);
                MethodInfo mi    = MatchParameters(methodinfo, types);
                return(Bind(inst, args, kw, mi, null));
            }
            return(null);
        }
Exemple #26
0
        internal Binding Bind(IntPtr inst, IntPtr pythonParametersPtr, IntPtr kw, MethodBase info, MethodInfo[] methodInfoArray)
        {
            // loop to find match, return invoker w/ or /wo error
            MethodBase[] _methods = null;
            // NOTE: return the size of the args pointer (the number of parameter from the python call)
            int pythonParameterCount = Runtime.PyTuple_Size(pythonParametersPtr);
            //WHY: Why is that so widely scoped ?
            object    pythonManagedParameterPtr;
            var       isGeneric            = false;
            ArrayList defaultParameterList = null;

            if (info != null)
            {
                // NOTE: If a MethodBase object has been provided, create an array with only it.
                // WHY a method base is provided some times and not other ? (ex: when call a genric with a type in [])
                _methods = new MethodBase[1];
                _methods.SetValue(info, 0);
            }
            else
            {
                // NOTE: Create an array of MethodBase from teh called method/constructor
                // WHY not use the methodinfo provided?
                _methods = GetMethods();
            }
            //WHY is it so widely scoped
            Type clrConvertedParameterType;

            // TODO: Clean up
            foreach (MethodBase methodInfo in _methods)
            {
                //WHY not just do isGeneric = mi.IsGenericMethod or use it directly ?
                if (methodInfo.IsGenericMethod)
                {
                    isGeneric = true;
                }
                //NOTE: Get the parameter from the current MethodBase
                //NOTE: MethodInfo Ok
                ParameterInfo[] clrParameterInfoArray = methodInfo.GetParameters();
                //NOTE: Get the number of clr parameters
                int clrParameterCount = clrParameterInfoArray.Length;

                var paramCountMatch = false;
                //REFACTOR: Use var like the other local variables
                var clrHasParamArray    = false;
                var clrParamsArrayStart = -1;

                var byRefCount = 0;

                if (pythonParameterCount == clrParameterCount)
                {
                    paramCountMatch = true;
                }
                else if (pythonParameterCount < clrParameterCount)
                {
                    paramCountMatch      = true;
                    defaultParameterList = new ArrayList();
                    for (int v = pythonParameterCount; v < clrParameterCount; v++)
                    {
                        if (clrParameterInfoArray[v].DefaultValue == DBNull.Value)
                        {
                            paramCountMatch = false;
                        }
                        else
                        {
                            defaultParameterList.Add(clrParameterInfoArray[v].DefaultValue);
                        }
                    }
                }
                else if (pythonParameterCount > clrParameterCount && clrParameterCount > 0 &&
                         Attribute.IsDefined(clrParameterInfoArray[clrParameterCount - 1], typeof(ParamArrayAttribute)))
                {
                    // This is a `foo({...}, params object[] bar)` style method
                    paramCountMatch     = true;
                    clrHasParamArray    = true;
                    clrParamsArrayStart = clrParameterCount - 1;
                }

                if (paramCountMatch)
                {
                    var methodParametersPtrArray = new object[clrParameterCount];

                    for (var n = 0; n < clrParameterCount; n++)
                    {
                        IntPtr pythonParameterPtr;
                        if (n < pythonParameterCount)
                        {
                            if (clrParamsArrayStart == n)
                            {
                                // map remaining Python arguments to a tuple since
                                // the managed function accepts it - hopefully :]
                                //WHY: Hmmm it returns a lot of python paramter as one. isn't there a problem later ?
                                pythonParameterPtr = Runtime.PyTuple_GetSlice(pythonParametersPtr, clrParamsArrayStart, pythonParameterCount);
                            }
                            else
                            {
                                pythonParameterPtr = Runtime.PyTuple_GetItem(pythonParametersPtr, n);
                            }

                            // this logic below handles cases when multiple overloading methods
                            // are ambiguous, hence comparison between Python and CLR types
                            // is necessary
                            clrConvertedParameterType = null;
                            IntPtr pythonParameterPtrType = IntPtr.Zero;
                            if (_methods.Length > 1)
                            {
                                pythonParameterPtrType = Runtime.PyObject_Type(pythonParameterPtr);
                                Exceptions.Clear();
                                if (pythonParameterPtrType != IntPtr.Zero)
                                {
                                    clrConvertedParameterType = Converter.GetTypeByAlias(pythonParameterPtrType);
                                }
                                Runtime.XDecref(pythonParameterPtrType);
                            }


                            if (clrConvertedParameterType != null)
                            {
                                var parameterTypeMatch = false;
                                if ((clrParameterInfoArray[n].ParameterType != typeof(object)) && (clrParameterInfoArray[n].ParameterType != clrConvertedParameterType))
                                {
                                    IntPtr pythonConvertedParameterPtrType = Converter.GetPythonTypeByAlias(clrParameterInfoArray[n].ParameterType);
                                    pythonParameterPtrType = Runtime.PyObject_Type(pythonParameterPtr);
                                    Exceptions.Clear();
                                    if (pythonParameterPtrType != IntPtr.Zero)
                                    {
                                        if (pythonConvertedParameterPtrType != pythonParameterPtrType)
                                        {
                                            parameterTypeMatch = false;
                                        }
                                        else
                                        {
                                            parameterTypeMatch        = true;
                                            clrConvertedParameterType = clrParameterInfoArray[n].ParameterType;
                                        }
                                    }
                                    if (!parameterTypeMatch)
                                    {
                                        // this takes care of enum values
                                        TypeCode clrParameterTypeCode          = Type.GetTypeCode(clrParameterInfoArray[n].ParameterType);
                                        TypeCode clrConvertedParameterTypeCode = Type.GetTypeCode(clrConvertedParameterType);
                                        if (clrParameterTypeCode == clrConvertedParameterTypeCode)
                                        {
                                            parameterTypeMatch        = true;
                                            clrConvertedParameterType = clrParameterInfoArray[n].ParameterType;
                                        }
                                    }
                                    Runtime.XDecref(pythonParameterPtrType);
                                    if (!parameterTypeMatch)
                                    {
                                        methodParametersPtrArray = null;
                                        break;
                                    }
                                }
                                else
                                {
                                    parameterTypeMatch        = true;
                                    clrConvertedParameterType = clrParameterInfoArray[n].ParameterType;
                                }
                            }
                            else
                            {
                                clrConvertedParameterType = clrParameterInfoArray[n].ParameterType;
                            }

                            if (clrParameterInfoArray[n].IsOut || clrConvertedParameterType.IsByRef)
                            {
                                byRefCount++;
                            }

                            if (!Converter.ToManaged(pythonParameterPtr, clrConvertedParameterType, out pythonManagedParameterPtr, false))
                            {
                                Exceptions.Clear();
                                methodParametersPtrArray = null;
                                break;
                            }
                            if (clrParamsArrayStart == n)
                            {
                                // GetSlice() creates a new reference but GetItem()
                                // returns only a borrow reference.
                                Runtime.XDecref(pythonParameterPtr);
                            }
                            methodParametersPtrArray[n] = pythonParameterPtr;
                        }
                        else
                        {
                            if (defaultParameterList != null)
                            {
                                methodParametersPtrArray[n] = defaultParameterList[n - pythonParameterCount];
                            }
                        }
                    }

                    if (methodParametersPtrArray == null)
                    {
                        continue;
                    }

                    object target = null;
                    if (!methodInfo.IsStatic && inst != IntPtr.Zero)
                    {
                        //CLRObject co = (CLRObject)ManagedType.GetManagedObject(inst);
                        // InvalidCastException: Unable to cast object of type
                        // 'Python.Runtime.ClassObject' to type 'Python.Runtime.CLRObject'
                        var co = ManagedType.GetManagedObject(inst) as CLRObject;

                        // Sanity check: this ensures a graceful exit if someone does
                        // something intentionally wrong like call a non-static method
                        // on the class rather than on an instance of the class.
                        // XXX maybe better to do this before all the other rigmarole.
                        if (co == null)
                        {
                            return(null);
                        }
                        target = co.inst;
                    }

                    return(new Binding(methodInfo, target, methodParametersPtrArray, byRefCount));
                }
            }
            // We weren't able to find a matching method but at least one
            // is a generic method and info is null. That happens when a generic
            // method was not called using the [] syntax. Let's introspect the
            // type of the arguments and use it to construct the correct method.
            if (isGeneric && info == null && methodInfoArray != null)
            {
                Type[]     types = Runtime.PythonArgsToTypeArray(pythonParametersPtr, true);
                MethodInfo mi    = MatchParameters(methodInfoArray, types);
                return(Bind(inst, pythonParametersPtr, kw, mi, null));
            }
            return(null);
        }
Exemple #27
0
 public override bool TryConvert(ConvertBinder binder, out object result)
 {
     return(Converter.ToManaged(this.obj, binder.Type, out result, false));
 }
Exemple #28
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);
            }
        }
Exemple #29
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.Interop.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);
            }

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

            for (var i = 0; i < count; i++)
            {
                IntPtr op = Runtime.Interop.PyTuple_GetItem(idx, i);
                index = Runtime.Interop.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);
        }
Exemple #30
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);
                    }

                    if (self.setterCache == null && !self.setterCacheFailed)
                    {
                        // if the setter is not public 'GetSetMethod' will not find it
                        // but calling 'SetValue' will work, so for backwards compatibility
                        // we will use it instead
                        self.setterCache = BuildSetter(self.info);
                        if (self.setterCache == null)
                        {
                            self.setterCacheFailed = true;
                        }
                    }

                    if (self.setterCacheFailed)
                    {
                        self.info.SetValue(co.inst, newval, null);
                    }
                    else
                    {
                        self.setterCache(co.inst, newval);
                    }
                }
                else
                {
                    self.info.SetValue(null, newval, null);
                }
                return(0);
            }
            catch (Exception e)
            {
                if (e.InnerException != null)
                {
                    e = e.InnerException;
                }
                Exceptions.SetError(e);
                return(-1);
            }
        }