/// <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 void SetError(Exception e) { // 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) { Runtime.XIncref(pe.PyType); Runtime.XIncref(pe.PyValue); Runtime.XIncref(pe.PyTB); Runtime.PyErr_Restore(pe.PyType, pe.PyValue, pe.PyTB); return; } IntPtr op = CLRObject.GetInstHandle(e); IntPtr etype = Runtime.PyObject_GetAttr(op, PyIdentifier.__class__); Runtime.PyErr_SetObject(new BorrowedReference(etype), new BorrowedReference(op)); Runtime.XDecref(etype); Runtime.XDecref(op); }
private void DisposeAll() { BeforeCollect?.Invoke(this, new CollectArgs() { ObjectCount = _objQueue.Count }); #if FINALIZER_CHECK lock (_queueLock) #endif { #if FINALIZER_CHECK ValidateRefCount(); #endif IntPtr obj; Runtime.PyErr_Fetch(out var errType, out var errVal, out var traceback); try { while (!_objQueue.IsEmpty) { if (!_objQueue.TryDequeue(out obj)) { continue; } Runtime.XDecref(obj); try { Runtime.CheckExceptionOccurred(); } catch (Exception e) { var errorArgs = new ErrorArgs { Error = e, }; ErrorHandler?.Invoke(this, errorArgs); if (!errorArgs.Handled) { throw new FinalizationException( "Python object finalization failed", disposable: obj, innerException: e); } } } } finally { // Python requires finalizers to preserve exception: // https://docs.python.org/3/extending/newtypes.html#finalization-and-de-allocation Runtime.PyErr_Restore(errType.StealNullable(), errVal.StealNullable(), traceback.StealNullable()); } } }
/// <summary> /// Restores python error. /// </summary> public void Restore() { IntPtr gs = PythonEngine.AcquireLock(); Runtime.PyErr_Restore(_pyType, _pyValue, _pyTB); _pyType = IntPtr.Zero; _pyValue = IntPtr.Zero; _pyTB = IntPtr.Zero; PythonEngine.ReleaseLock(gs); }
private void DisposeAll() { #if DEBUG // only used for testing CollectOnce?.Invoke(this, new CollectArgs() { ObjectCount = _objQueue.Count }); #endif #if FINALIZER_CHECK lock (_queueLock) #endif { #if FINALIZER_CHECK ValidateRefCount(); #endif IntPtr obj; Runtime.PyErr_Fetch(out var errType, out var errVal, out var traceback); try { while (_objQueue.TryDequeue(out obj)) { Runtime.XDecref(obj); try { Runtime.CheckExceptionOccurred(); } catch (Exception e) { var handler = ErrorHandler; if (handler is null) { throw new FinalizationException( "Python object finalization failed", disposable: obj, innerException: e); } handler.Invoke(this, new ErrorArgs() { Error = e }); } } } finally { // Python requires finalizers to preserve exception: // https://docs.python.org/3/extending/newtypes.html#finalization-and-de-allocation Runtime.PyErr_Restore(errType, errVal, traceback); } } }
private static void SetConversionError(IntPtr value, Type target) { // PyObject_Repr might clear the error Runtime.PyErr_Fetch(out var causeType, out var causeVal, out var causeTrace); IntPtr ob = Runtime.PyObject_Repr(value); string src = Runtime.GetManagedString(ob); Runtime.XDecref(ob); Runtime.PyErr_Restore(causeType.StealNullable(), causeVal.StealNullable(), causeTrace.StealNullable()); Exceptions.RaiseTypeError($"Cannot convert {src} to {target}"); }
internal static Exception?PeekCurrentOrNull(out ExceptionDispatchInfo?dispatchInfo) { using var _ = new Py.GILState(); Runtime.PyErr_Fetch(out var type, out var value, out var traceback); Runtime.PyErr_Restore( new NewReference(type, canBeNull: true).StealNullable(), new NewReference(value, canBeNull: true).StealNullable(), new NewReference(traceback, canBeNull: true).StealNullable()); var err = FetchCurrentOrNull(out dispatchInfo); Runtime.PyErr_Restore(type.StealNullable(), value.StealNullable(), traceback.StealNullable()); return(err); }
/// <summary> /// Dispose Method /// </summary> /// <remarks> /// The Dispose method provides a way to explicitly release the /// Python object represented by a PyObject instance. It is a good /// idea to call Dispose on PyObjects that wrap resources that are /// limited or need strict lifetime control. Otherwise, references /// to Python objects will not be released until a managed garbage /// collection occurs. /// </remarks> protected virtual void Dispose(bool disposing) { if (this.obj == IntPtr.Zero) { return; } if (Runtime.Py_IsInitialized() == 0) { throw new InvalidOperationException("Python runtime must be initialized"); } if (!Runtime.IsFinalizing) { long refcount = Runtime.Refcount(this.obj); Debug.Assert(refcount > 0, "Object refcount is 0 or less"); if (refcount == 1) { Runtime.PyErr_Fetch(out var errType, out var errVal, out var traceback); try { Runtime.XDecref(this.obj); Runtime.CheckExceptionOccurred(); } finally { // Python requires finalizers to preserve exception: // https://docs.python.org/3/extending/newtypes.html#finalization-and-de-allocation Runtime.PyErr_Restore(errType, errVal, traceback); } } else { Runtime.XDecref(this.obj); } } else { throw new InvalidOperationException("Runtime is already finalizing"); } this.obj = IntPtr.Zero; }
private static void SetConversionError(BorrowedReference value, Type target) { // PyObject_Repr might clear the error Runtime.PyErr_Fetch(out var causeType, out var causeVal, out var causeTrace); var ob = Runtime.PyObject_Repr(value); string src = "'object has no repr'"; if (ob.IsNull()) { Exceptions.Clear(); } else { src = Runtime.GetManagedString(ob.Borrow()) ?? src; } ob.Dispose(); Runtime.PyErr_Restore(causeType.StealNullable(), causeVal.StealNullable(), causeTrace.StealNullable()); Exceptions.RaiseTypeError($"Cannot convert {src} to {target}"); }
internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, MethodInfo[] methodinfo) { // No valid methods, nothing to bind. if (GetMethods().Length == 0) { var msg = new StringBuilder("The underlying C# method(s) have been deleted"); if (list.Count > 0 && list[0].Name != null) { msg.Append($": {list[0]}"); } return(Exceptions.RaiseTypeError(msg.ToString())); } Binding binding = Bind(inst, args, kw, info, methodinfo); object result; IntPtr ts = IntPtr.Zero; if (binding == null) { var value = new StringBuilder("No method matches given arguments"); if (methodinfo != null && methodinfo.Length > 0) { value.Append($" for {methodinfo[0].Name}"); } else if (list.Count > 0 && list[0].Valid) { value.Append($" for {list[0].Value.Name}"); } value.Append(": "); Runtime.PyErr_Fetch(out var errType, out var errVal, out var errTrace); AppendArgumentTypes(to: value, args); Runtime.PyErr_Restore(errType.StealNullable(), errVal.StealNullable(), errTrace.StealNullable()); Exceptions.RaiseTypeError(value.ToString()); return(IntPtr.Zero); } if (allow_threads) { ts = PythonEngine.BeginAllowThreads(); } try { result = binding.info.Invoke(binding.inst, BindingFlags.Default, null, binding.args, null); } catch (Exception e) { if (e.InnerException != null) { e = e.InnerException; } if (allow_threads) { PythonEngine.EndAllowThreads(ts); } Exceptions.SetError(e); return(IntPtr.Zero); } if (allow_threads) { PythonEngine.EndAllowThreads(ts); } // If there are out parameters, we return a tuple containing // the result, if any, followed by the out parameters. If there is only // one out parameter and the return type of the method is void, // we return the out parameter as the result to Python (for // code compatibility with ironpython). var mi = (MethodInfo)binding.info; if (binding.outs > 0) { ParameterInfo[] pi = mi.GetParameters(); int c = pi.Length; var n = 0; bool isVoid = mi.ReturnType == typeof(void); int tupleSize = binding.outs + (isVoid ? 0 : 1); IntPtr t = Runtime.PyTuple_New(tupleSize); if (!isVoid) { IntPtr v = Converter.ToPython(result, mi.ReturnType); Runtime.PyTuple_SetItem(t, n, v); n++; } for (var i = 0; i < c; i++) { Type pt = pi[i].ParameterType; if (pt.IsByRef) { IntPtr v = Converter.ToPython(binding.args[i], pt.GetElementType()); Runtime.PyTuple_SetItem(t, n, v); n++; } } if (binding.outs == 1 && mi.ReturnType == typeof(void)) { IntPtr v = Runtime.PyTuple_GetItem(t, 0); Runtime.XIncref(v); Runtime.XDecref(t); return(v); } return(t); } return(Converter.ToPython(result, mi.ReturnType)); }
/// <summary> /// Allows ctor selection to be limited to a single attempt at a /// match by providing the MethodBase to use instead of searching /// the entire MethodBinder.list (generic ArrayList) /// </summary> /// <param name="inst"> (possibly null) instance </param> /// <param name="args"> PyObject* to the arg tuple </param> /// <param name="kw"> PyObject* to the keyword args dict </param> /// <param name="info"> The sole ContructorInfo to use or null </param> /// <returns> The result of the constructor call with converted params </returns> /// <remarks> /// 2010-07-24 BC: I added the info parameter to the call to Bind() /// Binding binding = this.Bind(inst, args, kw, info); /// to take advantage of Bind()'s ability to use a single MethodBase (CI or MI). /// </remarks> internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info) { if (!_containingType.Valid) { return(Exceptions.RaiseTypeError(_containingType.DeletedMessage)); } object result; Type tp = _containingType.Value; if (tp.IsValueType && !tp.IsPrimitive && !tp.IsEnum && tp != typeof(decimal) && Runtime.PyTuple_Size(args) == 0) { // If you are trying to construct an instance of a struct by // calling its default constructor, that ConstructorInfo // instance will not appear in reflection and the object must // instead be constructed via a call to // Activator.CreateInstance(). try { result = Activator.CreateInstance(tp); } catch (Exception e) { if (e.InnerException != null) { e = e.InnerException; } Exceptions.SetError(e); return(null); } return(result); } Binding binding = Bind(inst, args, kw, info); if (binding == 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); binding = Bind(inst, eargs, IntPtr.Zero); Runtime.XDecref(eargs); if (binding == null) { var errorMessage = new StringBuilder("No constructor matches given arguments"); if (info != null && info.IsConstructor && info.DeclaringType != null) { errorMessage.Append(" for ").Append(info.DeclaringType.Name); } errorMessage.Append(": "); Runtime.PyErr_Fetch(out var errType, out var errVal, out var errTrace); AppendArgumentTypes(to: errorMessage, args); Runtime.PyErr_Restore(errType.StealNullable(), errVal.StealNullable(), errTrace.StealNullable()); Exceptions.RaiseTypeError(errorMessage.ToString()); return(null); } } // Fire the selected ctor and catch errors... var ci = (ConstructorInfo)binding.info; // Object construction is presumed to be non-blocking and fast // enough that we shouldn't really need to release the GIL. try { result = ci.Invoke(binding.args); } catch (Exception e) { if (e.InnerException != null) { e = e.InnerException; } Exceptions.SetError(e); return(null); } return(result); }