diff --git a/src/embed_tests/TestRuntime.cs b/src/embed_tests/TestRuntime.cs index 32369190c..4e05850c1 100644 --- a/src/embed_tests/TestRuntime.cs +++ b/src/embed_tests/TestRuntime.cs @@ -92,27 +92,29 @@ public static void PyCheck_Iter_PyObject_IsIterable_ThreadingLock_Test() { Runtime.Runtime.Py_Initialize(); - // Create an instance of threading.Lock, which is one of the very few types that does not have the - // TypeFlags.HaveIter set in Python 2. This tests a different code path in PyObject_IsIterable and PyIter_Check. - var threading = Runtime.Runtime.PyImport_ImportModule("threading"); - Exceptions.ErrorCheck(threading); - var threadingDict = Runtime.Runtime.PyModule_GetDict(threading); - Exceptions.ErrorCheck(threadingDict); - var lockType = Runtime.Runtime.PyDict_GetItemString(threadingDict, "Lock"); - if (lockType.IsNull) - throw new KeyNotFoundException("class 'Lock' was not found in 'threading'"); - - var args = Runtime.Runtime.PyTuple_New(0); - var lockInstance = Runtime.Runtime.PyObject_CallObject(lockType.DangerousGetAddress(), args); - Runtime.Runtime.XDecref(args); - Exceptions.ErrorCheck(lockInstance); - - Assert.IsFalse(Runtime.Runtime.PyObject_IsIterable(lockInstance)); - Assert.IsFalse(Runtime.Runtime.PyIter_Check(lockInstance)); - - threading.Dispose(); - - Runtime.Runtime.Py_Finalize(); + try + { + // Create an instance of threading.Lock, which is one of the very few types that does not have the + // TypeFlags.HaveIter set in Python 2. This tests a different code path in PyObject_IsIterable and PyIter_Check. + using var threading = Runtime.Runtime.PyImport_ImportModule("threading"); + Exceptions.ErrorCheck(threading); + var threadingDict = Runtime.Runtime.PyModule_GetDict(threading); + Exceptions.ErrorCheck(threadingDict); + var lockType = Runtime.Runtime.PyDict_GetItemString(threadingDict, "Lock"); + if (lockType.IsNull) + throw new PythonException(); + + using var args = NewReference.DangerousFromPointer(Runtime.Runtime.PyTuple_New(0)); + using var lockInstance = Runtime.Runtime.PyObject_CallObject(lockType, args); + Exceptions.ErrorCheck(lockInstance); + + Assert.IsFalse(Runtime.Runtime.PyObject_IsIterable(lockInstance)); + Assert.IsFalse(Runtime.Runtime.PyIter_Check(lockInstance)); + } + finally + { + Runtime.Runtime.Py_Finalize(); + } } } } diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index 6ebf885a0..232dd8708 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -1009,6 +1009,11 @@ internal static string PyObject_GetTypeName(IntPtr op) return Marshal.PtrToStringAnsi(ppName); } + /// + /// Test whether the Python object is an iterable. + /// + internal static bool PyObject_IsIterable(BorrowedReference ob) + => PyObject_IsIterable(ob.DangerousGetAddress()); /// /// Test whether the Python object is an iterable. /// @@ -1078,7 +1083,10 @@ internal static IntPtr PyObject_GetAttr(IntPtr pointer, IntPtr name) internal static IntPtr PyObject_Call(IntPtr pointer, IntPtr args, IntPtr kw) => Delegates.PyObject_Call(pointer, args, kw); - internal static IntPtr PyObject_CallObject(IntPtr pointer, IntPtr args) => Delegates.PyObject_CallObject(pointer, args); + internal static NewReference PyObject_CallObject(BorrowedReference callable, BorrowedReference args) => Delegates.PyObject_CallObject(callable, args); + internal static IntPtr PyObject_CallObject(IntPtr pointer, IntPtr args) + => Delegates.PyObject_CallObject(new BorrowedReference(pointer), new BorrowedReference(args)) + .DangerousMoveToPointerOrNull(); internal static int PyObject_RichCompareBool(IntPtr value1, IntPtr value2, int opid) => Delegates.PyObject_RichCompareBool(value1, value2, opid); @@ -1880,6 +1888,7 @@ internal static IntPtr PyTuple_GetSlice(IntPtr pointer, long start, long end) //==================================================================== // Python iterator API //==================================================================== + internal static bool PyIter_Check(BorrowedReference ob) => PyIter_Check(ob.DangerousGetAddress()); internal static bool PyIter_Check(IntPtr pointer) { @@ -2317,7 +2326,7 @@ static Delegates() PyObject_DelItem = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_DelItem), GetUnmanagedDll(_PythonDll)); PyObject_GetIter = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_GetIter), GetUnmanagedDll(_PythonDll)); PyObject_Call = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_Call), GetUnmanagedDll(_PythonDll)); - PyObject_CallObject = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_CallObject), GetUnmanagedDll(_PythonDll)); + PyObject_CallObject = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_CallObject), GetUnmanagedDll(_PythonDll)); PyObject_RichCompareBool = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_RichCompareBool), GetUnmanagedDll(_PythonDll)); PyObject_IsInstance = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_IsInstance), GetUnmanagedDll(_PythonDll)); PyObject_IsSubclass = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_IsSubclass), GetUnmanagedDll(_PythonDll)); @@ -2616,7 +2625,7 @@ static Delegates() internal static delegate* unmanaged[Cdecl] PyObject_DelItem { get; } internal static delegate* unmanaged[Cdecl] PyObject_GetIter { get; } internal static delegate* unmanaged[Cdecl] PyObject_Call { get; } - internal static delegate* unmanaged[Cdecl] PyObject_CallObject { get; } + internal static delegate* unmanaged[Cdecl] PyObject_CallObject { get; } internal static delegate* unmanaged[Cdecl] PyObject_RichCompareBool { get; } internal static delegate* unmanaged[Cdecl] PyObject_IsInstance { get; } internal static delegate* unmanaged[Cdecl] PyObject_IsSubclass { get; }