示例#1
0
        /// <summary>
        /// When called after SetError, sets the cause of the error.
        /// </summary>
        /// <param name="cause">The cause of the current error</param>
        public static void SetCause(Exception cause)
        {
            var currentException = PythonException.FetchCurrentRaw();

            currentException.Normalize();
            using var causeInstance = Converter.ToPythonReference(cause);
            Runtime.PyException_SetCause(currentException.Value !.Reference, causeInstance.Steal());
            currentException.Restore();
        }
示例#2
0
        /// <summary>
        /// SetError Method
        /// </summary>
        /// <remarks>
        /// Sets the current Python exception given a CLR exception
        /// object. The CLR exception instance is wrapped as a Python
        /// object, allowing it to be handled naturally from Python.
        /// </remarks>
        public static bool SetError(Exception e)
        {
            Debug.Assert(e is not null);

            // Because delegates allow arbitrary nesting of Python calling
            // managed calling Python calling... etc. it is possible that we
            // might get a managed exception raised that is a wrapper for a
            // Python exception. In that case we'd rather have the real thing.

            var pe = e as PythonException;

            if (pe != null)
            {
                pe.Restore();
                return(true);
            }

            using var instance = Converter.ToPythonReference(e);
            if (instance.IsNull())
            {
                return(false);
            }

            var exceptionInfo = ExceptionDispatchInfo.Capture(e);

            using var pyInfo = Converter.ToPythonReference(exceptionInfo);

            if (Runtime.PyObject_SetAttrString(instance, DispatchInfoAttribute, pyInfo) != 0)
            {
                return(false);
            }

            Debug.Assert(Runtime.PyObject_TypeCheck(instance, new BorrowedReference(BaseException)));

            var type = Runtime.PyObject_TYPE(instance);

            Runtime.PyErr_SetObject(type, instance);
            return(true);
        }
示例#3
0
        private object TrueDispatch(object[] args)
        {
            MethodInfo method = dtype.GetMethod("Invoke");

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

            NewReference op;

            using (var pyargs = NewReference.DangerousFromPointer(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.
                    var arg = Converter.ToPythonReference(args[i], pi[i].ParameterType);
                    if (arg.IsNull())
                    {
                        throw PythonException.ThrowLastAsClrException();
                    }
                    int res = Runtime.PyTuple_SetItem(pyargs, i, arg.Steal());
                    if (res != 0)
                    {
                        throw PythonException.ThrowLastAsClrException();
                    }
                }

                op = Runtime.PyObject_Call(target.Reference, pyargs, BorrowedReference.Null);
            }

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

            using (op)
            {
                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 object newArg, true))
                                {
                                    Exceptions.RaiseTypeError($"The Python function did not return {t.GetElementType()} (the out parameter type)");
                                    throw PythonException.ThrowLastAsClrException();
                                }
                                args[i] = newArg;
                                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 object newArg, true))
                                {
                                    Exceptions.RaiseTypeError($"The Python function returned a tuple where element {i} was not {t.GetElementType()} (the out parameter type)");
                                    throw PythonException.ThrowLastAsClrException();
                                }
                                args[i] = newArg;
                            }
                        }
                        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);
                }

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

                return(result);
            }
        }