/// <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(); }
/// <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); }
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); } }