diff --git a/src/embed_tests/TestConverter.cs b/src/embed_tests/TestConverter.cs index 71eb463bf..1657aaf79 100644 --- a/src/embed_tests/TestConverter.cs +++ b/src/embed_tests/TestConverter.cs @@ -94,7 +94,7 @@ public void CovertTypeError() [Test] public void ConvertOverflow() { - using (var num = new PyLong(ulong.MaxValue)) + using (var num = new PyInt(ulong.MaxValue)) { IntPtr largeNum = PyRuntime.PyNumber_Add(num.Handle, num.Handle); try diff --git a/src/embed_tests/TestFinalizer.cs b/src/embed_tests/TestFinalizer.cs index 1ae5c0390..28805ed6b 100644 --- a/src/embed_tests/TestFinalizer.cs +++ b/src/embed_tests/TestFinalizer.cs @@ -50,7 +50,7 @@ public void CollectBasicObject() }; Assert.IsFalse(called, "The event handler was called before it was installed"); - Finalizer.Instance.CollectOnce += handler; + Finalizer.Instance.BeforeCollect += handler; IntPtr pyObj = MakeAGarbage(out var shortWeak, out var longWeak); FullGCCollect(); @@ -81,7 +81,7 @@ public void CollectBasicObject() } finally { - Finalizer.Instance.CollectOnce -= handler; + Finalizer.Instance.BeforeCollect -= handler; } Assert.IsTrue(called, "The event handler was not called during finalization"); Assert.GreaterOrEqual(objectCount, 1); @@ -121,7 +121,7 @@ private static IntPtr MakeAGarbage(out WeakReference shortWeak, out WeakReferenc IntPtr handle = IntPtr.Zero; WeakReference @short = null, @long = null; // must create Python object in the thread where we have GIL - IntPtr val = PyLong.FromLong(1024); + IntPtr val = Runtime.Runtime.PyLong_FromLongLong(1024).DangerousMoveToPointerOrNull(); // must create temp object in a different thread to ensure it is not present // when conservatively scanning stack for GC roots. // see https://xamarin.github.io/bugzilla-archives/17/17593/bug.html @@ -234,7 +234,7 @@ private static IntPtr CreateStringGarbage() { PyString s1 = new PyString("test_string"); // s2 steal a reference from s1 - PyString s2 = new PyString(s1.Handle); + PyString s2 = new PyString(StolenReference.DangerousFromPointer(s1.Handle)); return s1.Handle; } } diff --git a/src/embed_tests/TestPyAnsiString.cs b/src/embed_tests/TestPyAnsiString.cs deleted file mode 100644 index b4a965ff7..000000000 --- a/src/embed_tests/TestPyAnsiString.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System; -using NUnit.Framework; -using Python.Runtime; - -namespace Python.EmbeddingTest -{ - public class TestPyAnsiString - { - [OneTimeSetUp] - public void SetUp() - { - PythonEngine.Initialize(); - } - - [OneTimeTearDown] - public void Dispose() - { - PythonEngine.Shutdown(); - } - - [Test] - public void TestStringCtor() - { - const string expected = "foo"; - var actual = new PyAnsiString(expected); - Assert.AreEqual(expected, actual.ToString()); - } - - [Test] - public void TestEmptyStringCtor() - { - const string expected = ""; - var actual = new PyAnsiString(expected); - Assert.AreEqual(expected, actual.ToString()); - } - - [Test] - public void TestPyObjectCtor() - { - const string expected = "Foo"; - - var t = new PyAnsiString(expected); - var actual = new PyAnsiString(t); - - Assert.AreEqual(expected, actual.ToString()); - } - - [Test] - public void TestBadPyObjectCtor() - { - var t = new PyInt(5); - PyAnsiString actual = null; - - var ex = Assert.Throws(() => actual = new PyAnsiString(t)); - - StringAssert.StartsWith("object is not a string", ex.Message); - Assert.IsNull(actual); - } - - [Test] - public void TestCtorPtr() - { - const string expected = "foo"; - - var t = new PyAnsiString(expected); - Runtime.Runtime.XIncref(t.Handle); - var actual = new PyAnsiString(t.Handle); - - Assert.AreEqual(expected, actual.ToString()); - } - - [Test] - public void IsStringTrue() - { - var t = new PyAnsiString("foo"); - - Assert.True(PyAnsiString.IsStringType(t)); - } - - [Test] - public void IsStringFalse() - { - var t = new PyInt(5); - - Assert.False(PyAnsiString.IsStringType(t)); - } - - [Test] - [Ignore("Ambiguous behavior between PY2/PY3")] - public void TestUnicode() - { - const string expected = "foo\u00e9"; - PyObject actual = new PyAnsiString(expected); - Assert.AreEqual(expected, actual.ToString()); - } - } -} diff --git a/src/embed_tests/TestPyFloat.cs b/src/embed_tests/TestPyFloat.cs index 906c8cb0d..36531cb6a 100644 --- a/src/embed_tests/TestPyFloat.cs +++ b/src/embed_tests/TestPyFloat.cs @@ -21,15 +21,6 @@ public void Dispose() PythonEngine.Shutdown(); } - [Test] - public void IntPtrCtor() - { - var i = new PyFloat(1); - Runtime.Runtime.XIncref(i.Handle); - var ii = new PyFloat(i.Handle); - Assert.AreEqual(i.Handle, ii.Handle); - } - [Test] public void FloatCtor() { diff --git a/src/embed_tests/TestPyInt.cs b/src/embed_tests/TestPyInt.cs index bd6cf23a1..efe046417 100644 --- a/src/embed_tests/TestPyInt.cs +++ b/src/embed_tests/TestPyInt.cs @@ -82,15 +82,6 @@ public void TestCtorSByte() Assert.AreEqual(i, a.ToInt32()); } - [Test] - public void TestCtorPtr() - { - var i = new PyInt(5); - Runtime.Runtime.XIncref(i.Handle); - var a = new PyInt(i.Handle); - Assert.AreEqual(5, a.ToInt32()); - } - [Test] public void TestCtorPyObject() { @@ -184,9 +175,10 @@ public void TestConvertToInt16() [Test] public void TestConvertToInt64() { - var a = new PyInt(5); + long val = 5 + (long)int.MaxValue; + var a = new PyInt(val); Assert.IsInstanceOf(typeof(long), a.ToInt64()); - Assert.AreEqual(5, a.ToInt64()); + Assert.AreEqual(val, a.ToInt64()); } } } diff --git a/src/embed_tests/TestPyLong.cs b/src/embed_tests/TestPyLong.cs deleted file mode 100644 index 6d587d064..000000000 --- a/src/embed_tests/TestPyLong.cs +++ /dev/null @@ -1,208 +0,0 @@ -using System; -using NUnit.Framework; -using Python.Runtime; - -namespace Python.EmbeddingTest -{ - public class TestPyLong - { - [OneTimeSetUp] - public void SetUp() - { - PythonEngine.Initialize(); - } - - [OneTimeTearDown] - public void Dispose() - { - PythonEngine.Shutdown(); - } - - [Test] - public void TestToInt64() - { - long largeNumber = 8L * 1024L * 1024L * 1024L; // 8 GB - var pyLargeNumber = new PyLong(largeNumber); - Assert.AreEqual(largeNumber, pyLargeNumber.ToInt64()); - } - - [Test] - public void TestCtorInt() - { - const int i = 5; - var a = new PyLong(i); - Assert.AreEqual(i, a.ToInt32()); - } - - [Test] - public void TestCtorUInt() - { - const uint i = 5; - var a = new PyLong(i); - Assert.AreEqual(i, a.ToInt32()); - } - - [Test] - public void TestCtorLong() - { - const long i = 5; - var a = new PyLong(i); - Assert.AreEqual(i, a.ToInt32()); - } - - [Test] - public void TestCtorULong() - { - const ulong i = 5; - var a = new PyLong(i); - Assert.AreEqual(i, a.ToInt32()); - } - - [Test] - public void TestCtorShort() - { - const short i = 5; - var a = new PyLong(i); - Assert.AreEqual(i, a.ToInt32()); - } - - [Test] - public void TestCtorUShort() - { - const ushort i = 5; - var a = new PyLong(i); - Assert.AreEqual(i, a.ToInt32()); - } - - [Test] - public void TestCtorByte() - { - const byte i = 5; - var a = new PyLong(i); - Assert.AreEqual(i, a.ToInt32()); - } - - [Test] - public void TestCtorSByte() - { - const sbyte i = 5; - var a = new PyLong(i); - Assert.AreEqual(i, a.ToInt32()); - } - - [Test] - public void TestCtorDouble() - { - double i = 5.0; - var a = new PyLong(i); - Assert.AreEqual(i, a.ToInt32()); - } - - [Test] - public void TestCtorPtr() - { - var i = new PyLong(5); - Runtime.Runtime.XIncref(i.Handle); - var a = new PyLong(i.Handle); - Assert.AreEqual(5, a.ToInt32()); - } - - [Test] - public void TestCtorPyObject() - { - var i = new PyLong(5); - Runtime.Runtime.XIncref(i.Handle); - var a = new PyLong(i); - Assert.AreEqual(5, a.ToInt32()); - } - - [Test] - public void TestCtorBadPyObject() - { - var i = new PyString("Foo"); - PyLong a = null; - - var ex = Assert.Throws(() => a = new PyLong(i)); - - StringAssert.StartsWith("object is not a long", ex.Message); - Assert.IsNull(a); - } - - [Test] - public void TestCtorString() - { - const string i = "5"; - var a = new PyLong(i); - Assert.AreEqual(5, a.ToInt32()); - } - - [Test] - public void TestCtorBadString() - { - const string i = "Foo"; - PyLong a = null; - - var ex = Assert.Throws(() => a = new PyLong(i)); - - StringAssert.StartsWith("invalid literal", ex.Message); - Assert.IsNull(a); - } - - [Test] - public void TestIsIntTypeTrue() - { - var i = new PyLong(5); - Assert.True(PyLong.IsLongType(i)); - } - - [Test] - public void TestIsLongTypeFalse() - { - var s = new PyString("Foo"); - Assert.False(PyLong.IsLongType(s)); - } - - [Test] - public void TestAsLongGood() - { - var i = new PyLong(5); - var a = PyLong.AsLong(i); - Assert.AreEqual(5, a.ToInt32()); - } - - [Test] - public void TestAsLongBad() - { - var s = new PyString("Foo"); - PyLong a = null; - - var ex = Assert.Throws(() => a = PyLong.AsLong(s)); - StringAssert.StartsWith("invalid literal", ex.Message); - Assert.IsNull(a); - } - - [Test] - public void TestConvertToInt32() - { - var a = new PyLong(5); - Assert.IsInstanceOf(typeof(int), a.ToInt32()); - Assert.AreEqual(5, a.ToInt32()); - } - - [Test] - public void TestConvertToInt16() - { - var a = new PyLong(5); - Assert.IsInstanceOf(typeof(short), a.ToInt16()); - Assert.AreEqual(5, a.ToInt16()); - } - - [Test] - public void TestConvertToInt64() - { - var a = new PyLong(5); - Assert.IsInstanceOf(typeof(long), a.ToInt64()); - Assert.AreEqual(5, a.ToInt64()); - } - } -} diff --git a/src/embed_tests/TestPyString.cs b/src/embed_tests/TestPyString.cs index 669ecde0d..b12e08c23 100644 --- a/src/embed_tests/TestPyString.cs +++ b/src/embed_tests/TestPyString.cs @@ -59,13 +59,12 @@ public void TestBadPyObjectCtor() } [Test] - public void TestCtorPtr() + public void TestCtorBorrowed() { const string expected = "foo"; var t = new PyString(expected); - Runtime.Runtime.XIncref(t.Handle); - var actual = new PyString(t.Handle); + var actual = new PyString(t.Reference); Assert.AreEqual(expected, actual.ToString()); } diff --git a/src/embed_tests/TestRuntime.cs b/src/embed_tests/TestRuntime.cs index 9fb2e8b22..b70e67195 100644 --- a/src/embed_tests/TestRuntime.cs +++ b/src/embed_tests/TestRuntime.cs @@ -68,20 +68,26 @@ public static void PyCheck_Iter_PyObject_IsIterable_Test() { Runtime.Runtime.Py_Initialize(); + Runtime.Native.ABI.Initialize(Runtime.Runtime.PyVersion); + // Tests that a python list is an iterable, but not an iterator - var pyList = Runtime.Runtime.PyList_New(0); - Assert.IsFalse(Runtime.Runtime.PyIter_Check(pyList)); - Assert.IsTrue(Runtime.Runtime.PyObject_IsIterable(pyList)); + using (var pyList = NewReference.DangerousFromPointer(Runtime.Runtime.PyList_New(0))) + { + Assert.IsFalse(Runtime.Runtime.PyIter_Check(pyList)); + Assert.IsTrue(Runtime.Runtime.PyObject_IsIterable(pyList)); - // Tests that a python list iterator is both an iterable and an iterator - var pyListIter = Runtime.Runtime.PyObject_GetIter(pyList); - Assert.IsTrue(Runtime.Runtime.PyObject_IsIterable(pyListIter)); - Assert.IsTrue(Runtime.Runtime.PyIter_Check(pyListIter)); + // Tests that a python list iterator is both an iterable and an iterator + using var pyListIter = Runtime.Runtime.PyObject_GetIter(pyList); + Assert.IsTrue(Runtime.Runtime.PyObject_IsIterable(pyListIter)); + Assert.IsTrue(Runtime.Runtime.PyIter_Check(pyListIter)); + } // Tests that a python float is neither an iterable nor an iterator - var pyFloat = Runtime.Runtime.PyFloat_FromDouble(2.73); - Assert.IsFalse(Runtime.Runtime.PyObject_IsIterable(pyFloat)); - Assert.IsFalse(Runtime.Runtime.PyIter_Check(pyFloat)); + using (var pyFloat = NewReference.DangerousFromPointer(Runtime.Runtime.PyFloat_FromDouble(2.73))) + { + Assert.IsFalse(Runtime.Runtime.PyObject_IsIterable(pyFloat)); + Assert.IsFalse(Runtime.Runtime.PyIter_Check(pyFloat)); + } Runtime.Runtime.Py_Finalize(); } @@ -91,6 +97,8 @@ public static void PyCheck_Iter_PyObject_IsIterable_ThreadingLock_Test() { Runtime.Runtime.Py_Initialize(); + Runtime.Native.ABI.Initialize(Runtime.Runtime.PyVersion); + try { // Create an instance of threading.Lock, which is one of the very few types that does not have the diff --git a/src/runtime/Codecs/EnumPyLongCodec.cs b/src/runtime/Codecs/EnumPyIntCodec.cs similarity index 80% rename from src/runtime/Codecs/EnumPyLongCodec.cs rename to src/runtime/Codecs/EnumPyIntCodec.cs index 7dab98028..5e6c4c7d3 100644 --- a/src/runtime/Codecs/EnumPyLongCodec.cs +++ b/src/runtime/Codecs/EnumPyIntCodec.cs @@ -3,9 +3,9 @@ namespace Python.Runtime.Codecs { [Obsolete] - public sealed class EnumPyLongCodec : IPyObjectEncoder, IPyObjectDecoder + public sealed class EnumPyIntCodec : IPyObjectEncoder, IPyObjectDecoder { - public static EnumPyLongCodec Instance { get; } = new EnumPyLongCodec(); + public static EnumPyIntCodec Instance { get; } = new EnumPyIntCodec(); public bool CanDecode(PyObject objectType, Type targetType) { @@ -25,7 +25,7 @@ public bool TryDecode(PyObject pyObj, out T value) Type etype = Enum.GetUnderlyingType(typeof(T)); - if (!PyLong.IsLongType(pyObj)) return false; + if (!PyInt.IsIntType(pyObj)) return false; object result; try @@ -55,14 +55,14 @@ public PyObject TryEncode(object value) try { - return new PyLong((long)value); + return new PyInt((long)value); } catch (InvalidCastException) { - return new PyLong((ulong)value); + return new PyInt((ulong)value); } } - private EnumPyLongCodec() { } + private EnumPyIntCodec() { } } } diff --git a/src/runtime/Codecs/TupleCodecs.cs b/src/runtime/Codecs/TupleCodecs.cs index 5ac55846f..ec740eef4 100644 --- a/src/runtime/Codecs/TupleCodecs.cs +++ b/src/runtime/Codecs/TupleCodecs.cs @@ -38,7 +38,7 @@ public PyObject TryEncode(object value) Runtime.PyTuple_SetItem(tuple, fieldIndex, pyItem); fieldIndex++; } - return new PyTuple(tuple); + return new PyTuple(StolenReference.DangerousFromPointer(tuple)); } public bool CanDecode(PyObject objectType, Type targetType) diff --git a/src/runtime/CollectionWrappers/IterableWrapper.cs b/src/runtime/CollectionWrappers/IterableWrapper.cs index 97979b59b..e20f11bcf 100644 --- a/src/runtime/CollectionWrappers/IterableWrapper.cs +++ b/src/runtime/CollectionWrappers/IterableWrapper.cs @@ -19,9 +19,13 @@ public IterableWrapper(PyObject pyObj) public IEnumerator GetEnumerator() { - PyObject iterObject = null; + PyObject iterObject; using (Py.GIL()) - iterObject = new PyObject(Runtime.PyObject_GetIter(pyObject.Handle)); + { + var iter = Runtime.PyObject_GetIter(pyObject.Reference); + PythonException.ThrowIfIsNull(iter); + iterObject = iter.MoveToPyObject(); + } while (true) { diff --git a/src/runtime/Util.cs b/src/runtime/Util.cs index f48bb5ab8..5fdb9e070 100644 --- a/src/runtime/Util.cs +++ b/src/runtime/Util.cs @@ -12,6 +12,8 @@ internal static class Util "This API is unstable, and might be changed or removed in the next minor release"; internal const string MinimalPythonVersionRequired = "Only Python 3.5 or newer is supported"; + internal const string InternalUseOnly = + "This API is for internal use only"; internal const string UseOverloadWithReferenceTypes = "This API is unsafe, and will be removed in the future. Use overloads working with *Reference types"; diff --git a/src/runtime/arrayobject.cs b/src/runtime/arrayobject.cs index ac2425001..297adf81c 100644 --- a/src/runtime/arrayobject.cs +++ b/src/runtime/arrayobject.cs @@ -147,7 +147,7 @@ static NewReference NewInstance(Type elementType, BorrowedReference arrayPyType, var items = obj.inst as Array; Type itemType = arrObj.type.Value.GetElementType(); int rank = items.Rank; - int index; + nint index; object value; // Note that CLR 1.0 only supports int indexes - methods to @@ -165,9 +165,9 @@ static NewReference NewInstance(Type elementType, BorrowedReference arrayPyType, { return RaiseIndexMustBeIntegerError(idx); } - index = Runtime.PyInt_AsLong(idx); + index = Runtime.PyLong_AsSignedSize_t(idx); - if (Exceptions.ErrorOccurred()) + if (index == -1 && Exceptions.ErrorOccurred()) { return Exceptions.RaiseTypeError("invalid index value"); } @@ -200,33 +200,33 @@ static NewReference NewInstance(Type elementType, BorrowedReference arrayPyType, var count = Runtime.PyTuple_Size(idx); - var args = new int[count]; + long[] indices = new long[count]; - for (var i = 0; i < count; i++) + for (int dimension = 0; dimension < count; dimension++) { - IntPtr op = Runtime.PyTuple_GetItem(idx, i); + IntPtr op = Runtime.PyTuple_GetItem(idx, dimension); if (!Runtime.PyInt_Check(op)) { return RaiseIndexMustBeIntegerError(op); } - index = Runtime.PyInt_AsLong(op); + index = Runtime.PyLong_AsSignedSize_t(op); - if (Exceptions.ErrorOccurred()) + if (index == -1 && Exceptions.ErrorOccurred()) { return Exceptions.RaiseTypeError("invalid index value"); } if (index < 0) { - index = items.GetLength(i) + index; + index = items.GetLength(dimension) + index; } - args.SetValue(index, i); + indices[dimension] = index; } try { - value = items.GetValue(args); + value = items.GetValue(indices); } catch (IndexOutOfRangeException) { @@ -247,7 +247,7 @@ static NewReference NewInstance(Type elementType, BorrowedReference arrayPyType, var items = obj.inst as Array; Type itemType = obj.inst.GetType().GetElementType(); int rank = items.Rank; - int index; + nint index; object value; if (items.IsReadOnly) @@ -268,9 +268,9 @@ static NewReference NewInstance(Type elementType, BorrowedReference arrayPyType, RaiseIndexMustBeIntegerError(idx); return -1; } - index = Runtime.PyInt_AsLong(idx); + index = Runtime.PyLong_AsSignedSize_t(idx); - if (Exceptions.ErrorOccurred()) + if (index == -1 && Exceptions.ErrorOccurred()) { Exceptions.RaiseTypeError("invalid index value"); return -1; @@ -301,19 +301,19 @@ static NewReference NewInstance(Type elementType, BorrowedReference arrayPyType, } var count = Runtime.PyTuple_Size(idx); - var args = new int[count]; + long[] indices = new long[count]; - for (var i = 0; i < count; i++) + for (int dimension = 0; dimension < count; dimension++) { - IntPtr op = Runtime.PyTuple_GetItem(idx, i); + IntPtr op = Runtime.PyTuple_GetItem(idx, dimension); if (!Runtime.PyInt_Check(op)) { RaiseIndexMustBeIntegerError(op); return -1; } - index = Runtime.PyInt_AsLong(op); + index = Runtime.PyLong_AsSignedSize_t(op); - if (Exceptions.ErrorOccurred()) + if (index == -1 && Exceptions.ErrorOccurred()) { Exceptions.RaiseTypeError("invalid index value"); return -1; @@ -321,15 +321,15 @@ static NewReference NewInstance(Type elementType, BorrowedReference arrayPyType, if (index < 0) { - index = items.GetLength(i) + index; + index = items.GetLength(dimension) + index; } - args.SetValue(index, i); + indices[dimension] = index; } try { - items.SetValue(value, args); + items.SetValue(value, indices); } catch (IndexOutOfRangeException) { diff --git a/src/runtime/classderived.cs b/src/runtime/classderived.cs index e0105afab..617c9d0d4 100644 --- a/src/runtime/classderived.cs +++ b/src/runtime/classderived.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Reflection; @@ -172,8 +173,7 @@ internal static Type CreateDerivedType(string name, var pyProperties = new HashSet(); if (py_dict != IntPtr.Zero && Runtime.PyDict_Check(py_dict)) { - Runtime.XIncref(py_dict); - using (var dict = new PyDict(py_dict)) + using var dict = new PyDict(new BorrowedReference(py_dict)); using (PyIterable keys = dict.Keys()) { foreach (PyObject pyKey in keys) @@ -221,8 +221,7 @@ internal static Type CreateDerivedType(string name, // Add any additional methods and properties explicitly exposed from Python. if (py_dict != IntPtr.Zero && Runtime.PyDict_Check(py_dict)) { - Runtime.XIncref(py_dict); - using (var dict = new PyDict(py_dict)) + using var dict = new PyDict(new BorrowedReference(py_dict)); using (PyIterable keys = dict.Keys()) { foreach (PyObject pyKey in keys) @@ -257,7 +256,9 @@ internal static Type CreateDerivedType(string name, Type.EmptyTypes); ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); +#pragma warning disable CS0618 // PythonDerivedType is for internal use only il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("Finalize")); +#pragma warning restore CS0618 // PythonDerivedType is for internal use only il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, baseClass.GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance)); il.Emit(OpCodes.Ret); @@ -329,7 +330,9 @@ private static void AddConstructor(ConstructorInfo ctor, Type baseType, TypeBuil il.Emit(OpCodes.Stelem, typeof(object)); } il.Emit(OpCodes.Ldloc_0); +#pragma warning disable CS0618 // PythonDerivedType is for internal use only il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeCtor")); +#pragma warning restore CS0618 // PythonDerivedType is for internal use only il.Emit(OpCodes.Ret); } @@ -407,6 +410,7 @@ private static void AddVirtualMethod(MethodInfo method, Type baseType, TypeBuild il.Emit(OpCodes.Stelem, typeof(object)); } il.Emit(OpCodes.Ldloc_0); +#pragma warning disable CS0618 // PythonDerivedType is for internal use only if (method.ReturnType == typeof(void)) { il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeMethodVoid")); @@ -416,6 +420,7 @@ private static void AddVirtualMethod(MethodInfo method, Type baseType, TypeBuild il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeMethod").MakeGenericMethod(method.ReturnType)); } +#pragma warning restore CS0618 // PythonDerivedType is for internal use only il.Emit(OpCodes.Ret); } @@ -489,6 +494,7 @@ private static void AddPythonMethod(string methodName, PyObject func, TypeBuilde il.Emit(OpCodes.Stelem, typeof(object)); } il.Emit(OpCodes.Ldloc_0); +#pragma warning disable CS0618 // PythonDerivedType is for internal use only if (returnType == typeof(void)) { il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeMethodVoid")); @@ -498,6 +504,7 @@ private static void AddPythonMethod(string methodName, PyObject func, TypeBuilde il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeMethod").MakeGenericMethod(returnType)); } +#pragma warning restore CS0618 // PythonDerivedType is for internal use only il.Emit(OpCodes.Ret); } } @@ -545,8 +552,10 @@ private static void AddPythonProperty(string propertyName, PyObject func, TypeBu ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldstr, propertyName); +#pragma warning disable CS0618 // PythonDerivedType is for internal use only il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeGetProperty").MakeGenericMethod(propertyType)); +#pragma warning restore CS0618 // PythonDerivedType is for internal use only il.Emit(OpCodes.Ret); propertyBuilder.SetGetMethod(methodBuilder); @@ -569,8 +578,10 @@ private static void AddPythonProperty(string propertyName, PyObject func, TypeBu il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldstr, propertyName); il.Emit(OpCodes.Ldarg_1); +#pragma warning disable CS0618 // PythonDerivedType is for internal use only il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeSetProperty").MakeGenericMethod(propertyType)); +#pragma warning restore CS0618 // PythonDerivedType is for internal use only il.Emit(OpCodes.Ret); propertyBuilder.SetSetMethod(methodBuilder); @@ -622,6 +633,8 @@ private static ModuleBuilder GetModuleBuilder(string assemblyName, string module /// This has to be public as it's called from methods on dynamically built classes /// potentially in other assemblies. /// + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete(Util.InternalUseOnly)] public class PythonDerivedType { /// diff --git a/src/runtime/converter.cs b/src/runtime/converter.cs index ba04933f7..4ef7ca46d 100644 --- a/src/runtime/converter.cs +++ b/src/runtime/converter.cs @@ -54,7 +54,7 @@ static Converter() if (op == Runtime.PyUnicodeType) return stringType; - if (op == Runtime.PyIntType) + if (op == Runtime.PyLongType) return int32Type; if (op == Runtime.PyLongType) @@ -75,13 +75,13 @@ internal static IntPtr GetPythonTypeByAlias(Type op) return Runtime.PyUnicodeType; if (op == int16Type) - return Runtime.PyIntType; + return Runtime.PyLongType; if (op == int32Type) - return Runtime.PyIntType; + return Runtime.PyLongType; if (op == int64Type) - return Runtime.PyIntType; + return Runtime.PyLongType; if (op == doubleType) return Runtime.PyFloatType; @@ -231,7 +231,7 @@ internal static IntPtr ToPython(object? value, Type type) return Runtime.PyInt_FromInt32((short)value); case TypeCode.Int64: - return Runtime.PyLong_FromLongLong((long)value); + return Runtime.PyLong_FromLongLong((long)value).DangerousMoveToPointerOrNull(); case TypeCode.Single: return Runtime.PyFloat_FromDouble((float)value); @@ -246,10 +246,10 @@ internal static IntPtr ToPython(object? value, Type type) return Runtime.PyInt_FromInt32((ushort)value); case TypeCode.UInt32: - return Runtime.PyLong_FromUnsignedLong((uint)value); + return Runtime.PyLong_FromUnsignedLongLong((uint)value).DangerousMoveToPointerOrNull(); case TypeCode.UInt64: - return Runtime.PyLong_FromUnsignedLongLong((ulong)value); + return Runtime.PyLong_FromUnsignedLongLong((ulong)value).DangerousMoveToPointerOrNull(); default: return CLRObject.GetInstHandle(value, type); @@ -457,7 +457,7 @@ internal static bool ToManagedValue(IntPtr value, Type obType, return true; } - if (value == Runtime.PyIntType || value == Runtime.PyLongType) + if (value == Runtime.PyLongType) { result = typeof(PyInt); return true; @@ -705,12 +705,12 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object? result, b { goto type_error; } - long num = Runtime.PyExplicitlyConvertToInt64(value); - if (num == -1 && Exceptions.ErrorOccurred()) + long? num = Runtime.PyLong_AsLongLong(value); + if (num is null) { goto convert_error; } - result = num; + result = num.Value; return true; } else @@ -757,12 +757,12 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object? result, b case TypeCode.UInt64: { - ulong num = Runtime.PyLong_AsUnsignedLongLong(value); - if (num == ulong.MaxValue && Exceptions.ErrorOccurred()) + ulong? num = Runtime.PyLong_AsUnsignedLongLong(value); + if (num is null) { goto convert_error; } - result = num; + result = num.Value; return true; } @@ -854,8 +854,8 @@ private static bool ToArray(IntPtr value, Type obType, out object? result, bool Type elementType = obType.GetElementType(); result = null; - IntPtr IterObject = Runtime.PyObject_GetIter(value); - if (IterObject == IntPtr.Zero) + using var IterObject = Runtime.PyObject_GetIter(new BorrowedReference(value)); + if (IterObject.IsNull()) { if (setError) { @@ -908,21 +908,18 @@ private static bool ToArray(IntPtr value, Type obType, out object? result, bool return false; } - IntPtr item; - - while ((item = Runtime.PyIter_Next(IterObject)) != IntPtr.Zero) + while (true) { + using var item = Runtime.PyIter_Next(IterObject); + if (item.IsNull()) break; + if (!Converter.ToManaged(item, elementType, out var obj, setError)) { - Runtime.XDecref(item); - Runtime.XDecref(IterObject); return false; } list.Add(obj); - Runtime.XDecref(item); } - Runtime.XDecref(IterObject); if (Exceptions.ErrorOccurred()) { diff --git a/src/runtime/delegatemanager.cs b/src/runtime/delegatemanager.cs index d4fc124fa..30c3cdfe9 100644 --- a/src/runtime/delegatemanager.cs +++ b/src/runtime/delegatemanager.cs @@ -61,7 +61,7 @@ private Type GetDispatcher(Type dtype) var cc = CallingConventions.Standard; Type[] args = { ptrtype, typetype }; ConstructorBuilder cb = tb.DefineConstructor(ma, cc, args); - ConstructorInfo ci = basetype.GetConstructor(args); + ConstructorInfo ci = basetype.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, args, null); ILGenerator il = cb.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); @@ -212,7 +212,7 @@ public class Dispatcher readonly PyObject target; readonly Type dtype; - public Dispatcher(IntPtr target, Type dtype) + protected Dispatcher(IntPtr target, Type dtype) { this.target = new PyObject(new BorrowedReference(target)); this.dtype = dtype; diff --git a/src/runtime/finalizer.cs b/src/runtime/finalizer.cs index cfff54070..5153c13ad 100644 --- a/src/runtime/finalizer.cs +++ b/src/runtime/finalizer.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -16,16 +17,21 @@ public class CollectArgs : EventArgs public class ErrorArgs : EventArgs { + public bool Handled { get; set; } public Exception Error { get; set; } } public static readonly Finalizer Instance = new Finalizer(); - public event EventHandler CollectOnce; + public event EventHandler BeforeCollect; public event EventHandler ErrorHandler; - public int Threshold { get; set; } - public bool Enable { get; set; } + const int DefaultThreshold = 200; + [DefaultValue(DefaultThreshold)] + public int Threshold { get; set; } = DefaultThreshold; + + [DefaultValue(true)] + public bool Enable { get; set; } = true; private ConcurrentQueue _objQueue = new ConcurrentQueue(); private int _throttled; @@ -34,24 +40,24 @@ public class ErrorArgs : EventArgs #if FINALIZER_CHECK private readonly object _queueLock = new object(); - public bool RefCountValidationEnabled { get; set; } = true; + internal bool RefCountValidationEnabled { get; set; } = true; #else - public readonly bool RefCountValidationEnabled = false; + internal bool RefCountValidationEnabled { get; set; } = false; #endif // Keep these declarations for compat even no FINALIZER_CHECK - public class IncorrectFinalizeArgs : EventArgs + internal class IncorrectFinalizeArgs : EventArgs { public IntPtr Handle { get; internal set; } public ICollection ImpactedObjects { get; internal set; } } - public class IncorrectRefCountException : Exception + internal class IncorrectRefCountException : Exception { public IntPtr PyPtr { get; internal set; } private string _message; public override string Message => _message; - public IncorrectRefCountException(IntPtr ptr) + internal IncorrectRefCountException(IntPtr ptr) { PyPtr = ptr; IntPtr pyname = Runtime.PyObject_Str(PyPtr); @@ -61,20 +67,14 @@ public IncorrectRefCountException(IntPtr ptr) } } - public delegate bool IncorrectRefCntHandler(object sender, IncorrectFinalizeArgs e); + internal delegate bool IncorrectRefCntHandler(object sender, IncorrectFinalizeArgs e); #pragma warning disable 414 - public event IncorrectRefCntHandler IncorrectRefCntResolver = null; + internal event IncorrectRefCntHandler IncorrectRefCntResolver = null; #pragma warning restore 414 - public bool ThrowIfUnhandleIncorrectRefCount { get; set; } = true; + internal bool ThrowIfUnhandleIncorrectRefCount { get; set; } = true; #endregion - private Finalizer() - { - Enable = true; - Threshold = 200; - } - public void Collect() => this.DisposeAll(); internal void ThrottledCollect() @@ -113,7 +113,7 @@ internal static void Shutdown() private void DisposeAll() { - CollectOnce?.Invoke(this, new CollectArgs() + BeforeCollect?.Invoke(this, new CollectArgs() { ObjectCount = _objQueue.Count }); @@ -141,18 +141,19 @@ private void DisposeAll() } catch (Exception e) { - var handler = ErrorHandler; - if (handler is null) + var errorArgs = new ErrorArgs + { + Error = e, + }; + + ErrorHandler?.Invoke(this, errorArgs); + + if (!errorArgs.Handled) { throw new FinalizationException( "Python object finalization failed", disposable: obj, innerException: e); } - - handler.Invoke(this, new ErrorArgs() - { - Error = e - }); } } } @@ -236,13 +237,27 @@ private void ValidateRefCount() public class FinalizationException : Exception { - public IntPtr PythonObject { get; } + public IntPtr Handle { get; } + + /// + /// Gets the object, whose finalization failed. + /// + /// If this function crashes, you can also try , + /// which does not attempt to increase the object reference count. + /// + public PyObject GetObject() => new(new BorrowedReference(this.Handle)); + /// + /// Gets the object, whose finalization failed without incrementing + /// its reference count. This should only ever be called during debugging. + /// When the result is disposed or finalized, the program will crash. + /// + public PyObject DebugGetObject() => new(this.Handle); public FinalizationException(string message, IntPtr disposable, Exception innerException) : base(message, innerException) { if (disposable == IntPtr.Zero) throw new ArgumentNullException(nameof(disposable)); - this.PythonObject = disposable; + this.Handle = disposable; } } } diff --git a/src/runtime/metatype.cs b/src/runtime/metatype.cs index 6c268dbcb..cbb7a148a 100644 --- a/src/runtime/metatype.cs +++ b/src/runtime/metatype.cs @@ -127,8 +127,7 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) // into python. if (IntPtr.Zero != dict) { - Runtime.XIncref(dict); - using (var clsDict = new PyDict(dict)) + using (var clsDict = new PyDict(new BorrowedReference(dict))) { if (clsDict.HasKey("__assembly__") || clsDict.HasKey("__namespace__")) { @@ -328,8 +327,7 @@ private static IntPtr DoInstanceCheck(IntPtr tp, IntPtr args, bool checkType) return Runtime.PyFalse; } - Runtime.XIncref(args); - using (var argsObj = new PyList(args)) + using (var argsObj = new PyList(new BorrowedReference(args))) { if (argsObj.Length() != 1) { diff --git a/src/runtime/native/ABI.cs b/src/runtime/native/ABI.cs index e99fc33ab..e651aa974 100644 --- a/src/runtime/native/ABI.cs +++ b/src/runtime/native/ABI.cs @@ -10,7 +10,7 @@ static class ABI public static int RefCountOffset { get; } = GetRefCountOffset(); public static int ObjectHeadOffset => RefCountOffset; - internal static void Initialize(Version version, BorrowedReference pyType) + internal static void Initialize(Version version) { string offsetsClassSuffix = string.Format(CultureInfo.InvariantCulture, "{0}{1}", version.Major, version.Minor); diff --git a/src/runtime/pyansistring.cs b/src/runtime/pyansistring.cs deleted file mode 100644 index 8a27104b1..000000000 --- a/src/runtime/pyansistring.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; - -namespace Python.Runtime -{ - public class PyAnsiString : PySequence - { - /// - /// PyAnsiString Constructor - /// - /// - /// Creates a new PyAnsiString from an existing object reference. Note - /// that the instance assumes ownership of the object reference. - /// The object reference is not checked for type-correctness. - /// - public PyAnsiString(IntPtr ptr) : base(ptr) - { - } - - - private static IntPtr FromObject(PyObject o) - { - if (o == null || !IsStringType(o)) - { - throw new ArgumentException("object is not a string"); - } - Runtime.XIncref(o.obj); - return o.obj; - } - - /// - /// PyString Constructor - /// - /// - /// Copy constructor - obtain a PyAnsiString from a generic PyObject. - /// An ArgumentException will be thrown if the given object is not - /// a Python string object. - /// - public PyAnsiString(PyObject o) : base(FromObject(o)) - { - } - private static IntPtr FromString(string s) - { - IntPtr val = Runtime.PyString_FromString(s); - PythonException.ThrowIfIsNull(val); - return val; - } - - - /// - /// PyAnsiString Constructor - /// - /// - /// Creates a Python string from a managed string. - /// - public PyAnsiString(string s) : base(FromString(s)) - { - } - - - /// - /// IsStringType Method - /// - /// - /// Returns true if the given object is a Python string. - /// - public static bool IsStringType(PyObject value) - { - return Runtime.PyString_Check(value.obj); - } - } -} diff --git a/src/runtime/pybuffer.cs b/src/runtime/pybuffer.cs index 9fe22aca7..7161a864f 100644 --- a/src/runtime/pybuffer.cs +++ b/src/runtime/pybuffer.cs @@ -3,7 +3,6 @@ using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; -using System.Text; namespace Python.Runtime { @@ -109,6 +108,7 @@ public bool IsContiguous(BufferOrderStyle order) /// public IntPtr GetPointer(long[] indices) { + if (indices is null) throw new ArgumentNullException(nameof(indices)); if (disposedValue) throw new ObjectDisposedException(nameof(PyBuffer)); if (Runtime.PyVersion < new Version(3, 7)) @@ -147,7 +147,7 @@ public void ToContiguous(IntPtr buf, BufferOrderStyle order) /// /// Fill the strides array with byte-strides of a contiguous (C-style if order is 'C' or Fortran-style if order is 'F') array of the given shape with the given number of bytes per element. /// - public static void FillContiguousStrides(int ndims, IntPtr shape, IntPtr strides, int itemsize, BufferOrderStyle order) + internal static void FillContiguousStrides(int ndims, IntPtr shape, IntPtr strides, int itemsize, BufferOrderStyle order) { Runtime.PyBuffer_FillContiguousStrides(ndims, shape, strides, itemsize, OrderStyleToChar(order, false)); } @@ -162,7 +162,7 @@ public static void FillContiguousStrides(int ndims, IntPtr shape, IntPtr strides /// If this function is used as part of a getbufferproc, exporter MUST be set to the exporting object and flags must be passed unmodified.Otherwise, exporter MUST be NULL. /// /// On success, set view->obj to a new reference to exporter and return 0. Otherwise, raise PyExc_BufferError, set view->obj to NULL and return -1; - public void FillInfo(IntPtr exporter, IntPtr buf, long len, bool _readonly, int flags) + internal void FillInfo(IntPtr exporter, IntPtr buf, long len, bool _readonly, int flags) { if (disposedValue) throw new ObjectDisposedException(nameof(PyBuffer)); @@ -187,6 +187,8 @@ public void Write(byte[] buffer, int offset, int count) throw new ArgumentOutOfRangeException("count", "Count is bigger than the python buffer."); if (_view.ndim != 1) throw new NotSupportedException("Multidimensional arrays, scalars and objects without a buffer are not supported."); + if (!this.IsContiguous(BufferOrderStyle.C)) + throw new NotImplementedException("Only continuous buffers are supported"); Marshal.Copy(buffer, offset, _view.buf, count); } @@ -203,6 +205,8 @@ public int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException("Multidimensional arrays, scalars and objects without a buffer are not supported."); if (_view.len.ToInt64() > int.MaxValue) throw new NotSupportedException("Python buffers bigger than int.MaxValue are not supported."); + if (!this.IsContiguous(BufferOrderStyle.C)) + throw new NotImplementedException("Only continuous buffers are supported"); int copylen = count < (int)_view.len ? count : (int)_view.len; Marshal.Copy(_view.buf, buffer, offset, copylen); diff --git a/src/runtime/pydict.cs b/src/runtime/pydict.cs index a715e2e08..4eb46b7bb 100644 --- a/src/runtime/pydict.cs +++ b/src/runtime/pydict.cs @@ -10,26 +10,12 @@ namespace Python.Runtime /// public class PyDict : PyIterable { - /// - /// PyDict Constructor - /// - /// - /// Creates a new PyDict from an existing object reference. Note - /// that the instance assumes ownership of the object reference. - /// The object reference is not checked for type-correctness. - /// - public PyDict(IntPtr ptr) : base(ptr) - { - } - internal PyDict(BorrowedReference reference) : base(reference) { } + internal PyDict(in StolenReference reference) : base(reference) { } /// - /// PyDict Constructor - /// - /// /// Creates a new Python dictionary object. - /// + /// public PyDict() : base(Runtime.PyDict_New()) { if (obj == IntPtr.Zero) @@ -40,16 +26,13 @@ public PyDict() : base(Runtime.PyDict_New()) /// - /// PyDict Constructor + /// Wraps existing dictionary object. /// - /// - /// Copy constructor - obtain a PyDict from a generic PyObject. An - /// ArgumentException will be thrown if the given object is not a - /// Python dictionary object. - /// - public PyDict(PyObject o) : base(o.obj) + /// + /// Thrown if the given object is not a Python dictionary object + /// + public PyDict(PyObject o) : base(o is null ? throw new ArgumentNullException(nameof(o)) : o.Reference) { - Runtime.XIncref(o.obj); if (!IsDictType(o)) { throw new ArgumentException("object is not a dict"); @@ -65,6 +48,7 @@ public PyDict(PyObject o) : base(o.obj) /// public static bool IsDictType(PyObject value) { + if (value is null) throw new ArgumentNullException(nameof(value)); return Runtime.PyDict_Check(value.obj); } @@ -77,6 +61,7 @@ public static bool IsDictType(PyObject value) /// public bool HasKey(PyObject key) { + if (key is null) throw new ArgumentNullException(nameof(key)); return Runtime.PyMapping_HasKey(obj, key.obj) != 0; } @@ -155,12 +140,12 @@ public PyIterable Items() /// public PyDict Copy() { - IntPtr op = Runtime.PyDict_Copy(obj); - if (op == IntPtr.Zero) + var op = Runtime.PyDict_Copy(Reference); + if (op.IsNull()) { throw PythonException.ThrowLastAsClrException(); } - return new PyDict(op); + return new PyDict(op.Steal()); } @@ -172,6 +157,8 @@ public PyDict Copy() /// public void Update(PyObject other) { + if (other is null) throw new ArgumentNullException(nameof(other)); + int result = Runtime.PyDict_Update(Reference, other.Reference); if (result < 0) { diff --git a/src/runtime/pyfloat.cs b/src/runtime/pyfloat.cs index a1752ff68..ef241f103 100644 --- a/src/runtime/pyfloat.cs +++ b/src/runtime/pyfloat.cs @@ -9,15 +9,7 @@ namespace Python.Runtime /// public class PyFloat : PyNumber { - /// - /// PyFloat Constructor - /// - /// - /// Creates a new PyFloat from an existing object reference. Note - /// that the instance assumes ownership of the object reference. - /// The object reference is not checked for type-correctness. - /// - public PyFloat(IntPtr ptr) : base(ptr) + internal PyFloat(in StolenReference ptr) : base(ptr) { } @@ -41,34 +33,37 @@ public PyFloat(PyObject o) : base(FromObject(o)) /// /// Creates a new Python float from a double value. /// - public PyFloat(double value) : base(FromDouble(value)) + public PyFloat(double value) : base(FromDouble(value).Steal()) { } - private static IntPtr FromObject(PyObject o) + private static BorrowedReference FromObject(PyObject o) { - if (o == null || !IsFloatType(o)) + if (o is null) throw new ArgumentNullException(nameof(o)); + + if (!IsFloatType(o)) { throw new ArgumentException("object is not a float"); } - Runtime.XIncref(o.obj); - return o.obj; + return o.Reference; } - private static IntPtr FromDouble(double value) + private static NewReference FromDouble(double value) { IntPtr val = Runtime.PyFloat_FromDouble(value); PythonException.ThrowIfIsNull(val); - return val; + return NewReference.DangerousFromPointer(val); } - private static IntPtr FromString(string value) + private static StolenReference FromString(string value) { + if (value is null) throw new ArgumentNullException(nameof(value)); + using (var s = new PyString(value)) { NewReference val = Runtime.PyFloat_FromString(s.Reference); PythonException.ThrowIfIsNull(val); - return val.DangerousMoveToPointerOrNull(); + return val.Steal(); } } @@ -91,23 +86,23 @@ public PyFloat(string value) : base(FromString(value)) /// public static bool IsFloatType(PyObject value) { + if (value is null) throw new ArgumentNullException(nameof(value)); return Runtime.PyFloat_Check(value.obj); } /// - /// AsFloat Method - /// - /// /// Convert a Python object to a Python float if possible, raising /// a PythonException if the conversion is not possible. This is /// equivalent to the Python expression "float(object)". - /// + /// public static PyFloat AsFloat(PyObject value) { - IntPtr op = Runtime.PyNumber_Float(value.obj); + if (value is null) throw new ArgumentNullException(nameof(value)); + + var op = Runtime.PyNumber_Float(value.Reference); PythonException.ThrowIfIsNull(op); - return new PyFloat(op); + return new PyFloat(op.Steal()); } } } diff --git a/src/runtime/pyint.cs b/src/runtime/pyint.cs index f7e4cdf62..9b5835ae8 100644 --- a/src/runtime/pyint.cs +++ b/src/runtime/pyint.cs @@ -10,15 +10,7 @@ namespace Python.Runtime /// public class PyInt : PyNumber { - /// - /// PyInt Constructor - /// - /// - /// Creates a new PyInt from an existing object reference. Note - /// that the instance assumes ownership of the object reference. - /// The object reference is not checked for type-correctness. - /// - public PyInt(IntPtr ptr) : base(ptr) + internal PyInt(in StolenReference ptr) : base(ptr) { } @@ -40,21 +32,21 @@ public PyInt(PyObject o) : base(FromObject(o)) { } - private static IntPtr FromObject(PyObject o) + private static BorrowedReference FromObject(PyObject o) { - if (o == null || !IsIntType(o)) + if (o is null) throw new ArgumentNullException(nameof(o)); + if (!IsIntType(o)) { throw new ArgumentException("object is not an int"); } - Runtime.XIncref(o.obj); - return o.obj; + return o.Reference; } - private static IntPtr FromInt(int value) + private static NewReference FromInt(int value) { IntPtr val = Runtime.PyInt_FromInt32(value); PythonException.ThrowIfIsNull(val); - return val; + return NewReference.DangerousFromPointer(val); } /// @@ -63,7 +55,7 @@ private static IntPtr FromInt(int value) /// /// Creates a new Python int from an int32 value. /// - public PyInt(int value) : base(FromInt(value)) + public PyInt(int value) : base(FromInt(value).Steal()) { } @@ -89,22 +81,25 @@ public PyInt(long value) : base(FromLong(value)) { } - private static IntPtr FromLong(long value) + private static StolenReference FromLong(long value) { - IntPtr val = Runtime.PyInt_FromInt64(value); + var val = Runtime.PyInt_FromInt64(value); PythonException.ThrowIfIsNull(val); - return val; + return val.Steal(); } - /// - /// PyInt Constructor + /// Creates a new Python int from a value. /// - /// - /// Creates a new Python int from a uint64 value. - /// - public PyInt(ulong value) : base(FromLong((long)value)) + public PyInt(ulong value) : base(FromUInt64(value)) + { + } + + private static StolenReference FromUInt64(ulong value) { + var val = Runtime.PyLong_FromUnsignedLongLong(value); + PythonException.ThrowIfIsNull(val); + return val.Steal(); } @@ -152,11 +147,11 @@ public PyInt(sbyte value) : this((int)value) } - private static IntPtr FromString(string value) + private static StolenReference FromString(string value) { - IntPtr val = Runtime.PyLong_FromString(value, IntPtr.Zero, 0); + NewReference val = Runtime.PyLong_FromString(value, 0); PythonException.ThrowIfIsNull(val); - return val; + return val.Steal(); } /// @@ -178,23 +173,22 @@ public PyInt(string value) : base(FromString(value)) /// public static bool IsIntType(PyObject value) { + if (value is null) throw new ArgumentNullException(nameof(value)); return Runtime.PyInt_Check(value.obj); } /// - /// AsInt Method - /// - /// /// Convert a Python object to a Python int if possible, raising /// a PythonException if the conversion is not possible. This is /// equivalent to the Python expression "int(object)". - /// + /// public static PyInt AsInt(PyObject value) { - IntPtr op = Runtime.PyNumber_Int(value.obj); + if (value is null) throw new ArgumentNullException(nameof(value)); + var op = Runtime.PyNumber_Long(value.Reference); PythonException.ThrowIfIsNull(op); - return new PyInt(op); + return new PyInt(op.Steal()); } @@ -211,16 +205,9 @@ public short ToInt16() /// - /// ToInt32 Method + /// Return the value of the Python int object as an . /// - /// - /// Return the value of the Python int object as an int32. - /// - public int ToInt32() - { - return Runtime.PyInt_AsLong(obj); - } - + public int ToInt32() => Converter.ToInt32(Reference); /// /// ToInt64 Method @@ -230,7 +217,12 @@ public int ToInt32() /// public long ToInt64() { - return Convert.ToInt64(ToInt32()); + long? val = Runtime.PyLong_AsLongLong(obj); + if (val is null) + { + throw PythonException.ThrowLastAsClrException(); + } + return val.Value; } } } diff --git a/src/runtime/pyiter.cs b/src/runtime/pyiter.cs index 72e967be2..3a734828f 100644 --- a/src/runtime/pyiter.cs +++ b/src/runtime/pyiter.cs @@ -21,7 +21,7 @@ public class PyIter : PyObject, IEnumerator /// that the instance assumes ownership of the object reference. /// The object reference is not checked for type-correctness. /// - public PyIter(IntPtr ptr) : base(ptr) + internal PyIter(in StolenReference reference) : base(reference) { } @@ -42,22 +42,19 @@ static BorrowedReference FromPyObject(PyObject pyObject) { internal PyIter(BorrowedReference reference) : base(reference) { } /// - /// PyIter factory function. + /// Create a new from a given iterable. + /// + /// Like doing "iter()" in Python. /// - /// - /// Create a new PyIter from a given iterable. Like doing "iter(iterable)" in python. - /// - /// - /// public static PyIter GetIter(PyObject iterable) { if (iterable == null) { throw new ArgumentNullException(); } - IntPtr val = Runtime.PyObject_GetIter(iterable.obj); + var val = Runtime.PyObject_GetIter(iterable.Reference); PythonException.ThrowIfIsNull(val); - return new PyIter(val); + return new PyIter(val.Steal()); } protected override void Dispose(bool disposing) diff --git a/src/runtime/pylist.cs b/src/runtime/pylist.cs index 8f346524f..616372f7b 100644 --- a/src/runtime/pylist.cs +++ b/src/runtime/pylist.cs @@ -10,32 +10,20 @@ namespace Python.Runtime /// public class PyList : PySequence { - /// - /// PyList Constructor - /// - /// - /// Creates a new PyList from an existing object reference. Note - /// that the instance assumes ownership of the object reference. - /// The object reference is not checked for type-correctness. - /// - public PyList(IntPtr ptr) : base(ptr) - { - } - + internal PyList(in StolenReference reference) : base(reference) { } /// /// Creates new pointing to the same object, as the given reference. /// internal PyList(BorrowedReference reference) : base(reference) { } - private static IntPtr FromObject(PyObject o) + private static BorrowedReference FromObject(PyObject o) { if (o == null || !IsListType(o)) { throw new ArgumentException("object is not a list"); } - Runtime.XIncref(o.obj); - return o.obj; + return o.Reference; } /// @@ -52,21 +40,23 @@ public PyList(PyObject o) : base(FromObject(o)) /// - /// PyList Constructor - /// - /// /// Creates a new empty Python list object. - /// - public PyList() : base(Runtime.PyList_New(0)) + /// + public PyList() : base(NewEmtpy().Steal()) { - if (obj == IntPtr.Zero) - { - throw PythonException.ThrowLastAsClrException(); - } } - private static IntPtr FromArray(PyObject[] items) + private static NewReference NewEmtpy() { + IntPtr ptr = Runtime.PyList_New(0); + PythonException.ThrowIfIsNull(ptr); + return NewReference.DangerousFromPointer(ptr); + } + + private static NewReference FromArray(PyObject[] items) + { + if (items is null) throw new ArgumentNullException(nameof(items)); + int count = items.Length; IntPtr val = Runtime.PyList_New(count); for (var i = 0; i < count; i++) @@ -80,59 +70,53 @@ private static IntPtr FromArray(PyObject[] items) throw PythonException.ThrowLastAsClrException(); } } - return val; + return NewReference.DangerousFromPointer(val); } /// - /// PyList Constructor + /// Creates a new Python list object from an array of objects. /// - /// - /// Creates a new Python list object from an array of PyObjects. - /// - public PyList(PyObject[] items) : base(FromArray(items)) + public PyList(PyObject[] items) : base(FromArray(items).Steal()) { } /// - /// IsListType Method - /// - /// /// Returns true if the given object is a Python list. - /// + /// public static bool IsListType(PyObject value) { + if (value is null) throw new ArgumentNullException(nameof(value)); + return Runtime.PyList_Check(value.obj); } /// - /// AsList Method - /// - /// /// Converts a Python object to a Python list if possible, raising /// a PythonException if the conversion is not possible. This is /// equivalent to the Python expression "list(object)". - /// + /// public static PyList AsList(PyObject value) { - IntPtr op = Runtime.PySequence_List(value.obj); - if (op == IntPtr.Zero) + if (value is null) throw new ArgumentNullException(nameof(value)); + + NewReference op = Runtime.PySequence_List(value.Reference); + if (op.IsNull()) { throw PythonException.ThrowLastAsClrException(); } - return new PyList(op); + return new PyList(op.Steal()); } /// - /// Append Method - /// - /// /// Append an item to the list object. - /// + /// public void Append(PyObject item) { - int r = Runtime.PyList_Append(this.Reference, new BorrowedReference(item.obj)); + if (item is null) throw new ArgumentNullException(nameof(item)); + + int r = Runtime.PyList_Append(this.Reference, item.Reference); if (r < 0) { throw PythonException.ThrowLastAsClrException(); @@ -140,13 +124,12 @@ public void Append(PyObject item) } /// - /// Insert Method - /// - /// /// Insert an item in the list object at the given index. - /// + /// public void Insert(int index, PyObject item) { + if (item is null) throw new ArgumentNullException(nameof(item)); + int r = Runtime.PyList_Insert(this.Reference, index, item.obj); if (r < 0) { diff --git a/src/runtime/pylong.cs b/src/runtime/pylong.cs deleted file mode 100644 index 8cb814cf6..000000000 --- a/src/runtime/pylong.cs +++ /dev/null @@ -1,249 +0,0 @@ -using System; - -namespace Python.Runtime -{ - /// - /// Represents a Python long int object. See the documentation at - /// PY2: https://docs.python.org/2/c-api/long.html - /// PY3: https://docs.python.org/3/c-api/long.html - /// for details. - /// - public class PyLong : PyNumber - { - /// - /// PyLong Constructor - /// - /// - /// Creates a new PyLong from an existing object reference. Note - /// that the instance assumes ownership of the object reference. - /// The object reference is not checked for type-correctness. - /// - public PyLong(IntPtr ptr) : base(ptr) - { - } - - - /// - /// PyLong Constructor - /// - /// - /// Copy constructor - obtain a PyLong from a generic PyObject. An - /// ArgumentException will be thrown if the given object is not a - /// Python long object. - /// - public PyLong(PyObject o) : base(FromObject(o)) - { - } - - private static IntPtr FromObject(PyObject o) - { - if (o == null || !IsLongType(o)) - { - throw new ArgumentException("object is not a long"); - } - Runtime.XIncref(o.obj); - return o.obj; - } - - private static IntPtr FromInt(int value) - { - IntPtr val = Runtime.PyLong_FromLong(value); - PythonException.ThrowIfIsNull(val); - return val; - } - - /// - /// PyLong Constructor - /// - /// - /// Creates a new PyLong from an int32 value. - /// - public PyLong(int value) : base(FromInt(value)) - { - } - - - /// - /// PyLong Constructor - /// - /// - /// Creates a new PyLong from a uint32 value. - /// - public PyLong(uint value) : base(FromInt((int)value)) - { - } - - - internal static IntPtr FromLong(long value) - { - IntPtr val = Runtime.PyLong_FromLongLong(value); - PythonException.ThrowIfIsNull(val); - return val; - } - - /// - /// PyLong Constructor - /// - /// - /// Creates a new PyLong from an int64 value. - /// - public PyLong(long value) : base(FromLong(value)) - { - } - - private static IntPtr FromULong(ulong value) - { - IntPtr val = Runtime.PyLong_FromUnsignedLongLong(value); - PythonException.ThrowIfIsNull(val); - return val; - } - - /// - /// PyLong Constructor - /// - /// - /// Creates a new PyLong from a uint64 value. - /// - public PyLong(ulong value) : base(FromULong(value)) - { - } - - - /// - /// PyLong Constructor - /// - /// - /// Creates a new PyLong from an int16 value. - /// - public PyLong(short value) : base(FromInt((int)value)) - { - } - - - /// - /// PyLong Constructor - /// - /// - /// Creates a new PyLong from an uint16 value. - /// - public PyLong(ushort value) : base(FromInt((int)value)) - { - } - - - /// - /// PyLong Constructor - /// - /// - /// Creates a new PyLong from a byte value. - /// - public PyLong(byte value) : base(FromInt((int)value)) - { - } - - - /// - /// PyLong Constructor - /// - /// - /// Creates a new PyLong from an sbyte value. - /// - public PyLong(sbyte value) : base(FromInt((int)value)) - { - } - - private static IntPtr FromDouble(double value) - { - IntPtr val = Runtime.PyLong_FromDouble(value); - PythonException.ThrowIfIsNull(val); - return val; - } - - /// - /// PyLong Constructor - /// - /// - /// Creates a new PyLong from an double value. - /// - public PyLong(double value) : base(FromDouble(value)) - { - } - - private static IntPtr FromString(string value) - { - IntPtr val = Runtime.PyLong_FromString(value, IntPtr.Zero, 0); - PythonException.ThrowIfIsNull(val); - return val; - } - - /// - /// PyLong Constructor - /// - /// - /// Creates a new PyLong from a string value. - /// - public PyLong(string value) : base(FromString(value)) - { - } - - - /// - /// Returns true if the given object is a Python long. - /// - public static bool IsLongType(PyObject value) - { - return Runtime.PyLong_Check(value.obj); - } - - - /// - /// AsLong Method - /// - /// - /// Convert a Python object to a Python long if possible, raising - /// a PythonException if the conversion is not possible. This is - /// equivalent to the Python expression "long(object)". - /// - public static PyLong AsLong(PyObject value) - { - IntPtr op = Runtime.PyNumber_Long(value.obj); - PythonException.ThrowIfIsNull(op); - return new PyLong(op); - } - - /// - /// ToInt16 Method - /// - /// - /// Return the value of the Python long object as an int16. - /// - public short ToInt16() - { - return Convert.ToInt16(ToInt64()); - } - - - /// - /// ToInt32 Method - /// - /// - /// Return the value of the Python long object as an int32. - /// - public int ToInt32() - { - return Convert.ToInt32(ToInt64()); - } - - - /// - /// ToInt64 Method - /// - /// - /// Return the value of the Python long object as an int64. - /// - public long ToInt64() - { - return Runtime.PyExplicitlyConvertToInt64(obj); - } - } -} diff --git a/src/runtime/pynumber.cs b/src/runtime/pynumber.cs index 9c2699d6b..442be230e 100644 --- a/src/runtime/pynumber.cs +++ b/src/runtime/pynumber.cs @@ -13,11 +13,8 @@ namespace Python.Runtime /// public class PyNumber : PyObject { - protected PyNumber(IntPtr ptr) : base(ptr) - { - } - - internal PyNumber(BorrowedReference reference): base(reference) { } + internal PyNumber(in StolenReference reference) : base(reference) { } + internal PyNumber(BorrowedReference reference) : base(reference) { } /// /// IsNumberType Method @@ -27,6 +24,8 @@ internal PyNumber(BorrowedReference reference): base(reference) { } /// public static bool IsNumberType(PyObject value) { + if (value is null) throw new ArgumentNullException(nameof(value)); + return Runtime.PyNumber_Check(value.obj); } } diff --git a/src/runtime/pyobject.cs b/src/runtime/pyobject.cs index f1e72df9c..635adbd74 100644 --- a/src/runtime/pyobject.cs +++ b/src/runtime/pyobject.cs @@ -40,7 +40,7 @@ public partial class PyObject : DynamicObject, IDisposable /// and the reference will be DECREFed when the PyObject is garbage /// collected or explicitly disposed. /// - public PyObject(IntPtr ptr) + internal PyObject(IntPtr ptr) { if (ptr == IntPtr.Zero) throw new ArgumentNullException(nameof(ptr)); @@ -104,12 +104,9 @@ internal PyObject(in StolenReference reference) /// - /// Handle Property - /// - /// /// Gets the native handle of the underlying Python object. This /// value is generally for internal use by the PythonNet runtime. - /// + /// public IntPtr Handle { get { return obj; } @@ -254,7 +251,7 @@ public PyObject GetPythonType() /// Returns true if the object o is of type typeOrClass or a subtype /// of typeOrClass. /// - public bool TypeCheck(PyObject typeOrClass) + public bool TypeCheck(PyType typeOrClass) { if (typeOrClass == null) throw new ArgumentNullException(nameof(typeOrClass)); @@ -686,22 +683,11 @@ public virtual PyObject this[int index] /// - /// GetIterator Method - /// - /// /// Return a new (Python) iterator for the object. This is equivalent - /// to the Python expression "iter(object)". A PythonException will be - /// raised if the object cannot be iterated. - /// - public PyObject GetIterator() - { - IntPtr r = Runtime.PyObject_GetIter(obj); - if (r == IntPtr.Zero) - { - throw PythonException.ThrowLastAsClrException(); - } - return new PyObject(r); - } + /// to the Python expression "iter(object)". + /// + /// Thrown if the object can not be iterated. + public PyIter GetIterator() => PyIter.GetIter(this); /// /// Invoke Method @@ -1010,7 +996,7 @@ public PyList Dir() { throw PythonException.ThrowLastAsClrException(); } - return new PyList(r); + return new PyList(NewReference.DangerousFromPointer(r).Steal()); } @@ -1147,7 +1133,7 @@ private void GetArgs(object[] inargs, CallInfo callInfo, out PyTuple args, out P { AddArgument(argTuple, i, inargs[i]); } - args = new PyTuple(argTuple); + args = new PyTuple(StolenReference.DangerousFromPointer(argTuple)); var namedArgs = new object[namedArgumentCount * 2]; for (int i = 0; i < namedArgumentCount; ++i) @@ -1170,7 +1156,7 @@ private void GetArgs(object[] inargs, out PyTuple args, out PyDict kwargs) { AddArgument(argtuple, i, inargs[i]); } - args = new PyTuple(argtuple); + args = new PyTuple(StolenReference.DangerousFromPointer(argtuple)); kwargs = null; for (int i = arg_count; i < inargs.Length; i++) diff --git a/src/runtime/pyscope.cs b/src/runtime/pyscope.cs index 315eb75e5..66c299811 100644 --- a/src/runtime/pyscope.cs +++ b/src/runtime/pyscope.cs @@ -79,8 +79,7 @@ private PyScope(IntPtr ptr, PyScopeManager manager) : base(ptr) /// public PyDict Variables() { - Runtime.XIncref(variables); - return new PyDict(variables); + return new PyDict(VarsRef); } /// @@ -101,7 +100,7 @@ public PyScope NewScope() /// Import a scope or a module of given name, /// scope will be looked up first. /// - public dynamic Import(string name, string asname = null) + public PyObject Import(string name, string asname = null) { Check(); if (String.IsNullOrEmpty(asname)) @@ -124,25 +123,22 @@ public dynamic Import(string name, string asname = null) } /// - /// Import method - /// - /// /// Import a scope as a variable of given name. - /// + /// public void Import(PyScope scope, string asname) { + if (scope is null) throw new ArgumentNullException(nameof(scope)); this.SetPyValue(asname, scope.Handle); } /// - /// Import Method - /// - /// /// The 'import .. as ..' statement in Python. /// Import a module as a variable into the scope. - /// + /// public void Import(PyObject module, string asname = null) { + if (module is null) throw new ArgumentNullException(nameof(module)); + if (String.IsNullOrEmpty(asname)) { asname = module.GetAttr("__name__").As(); @@ -151,12 +147,9 @@ public void Import(PyObject module, string asname = null) } /// - /// ImportAll Method - /// - /// /// The 'import * from ..' statement in Python. /// Import all content of a scope/module of given name into the scope, scope will be looked up first. - /// + /// public void ImportAll(string name) { PyScope scope; @@ -174,13 +167,12 @@ public void ImportAll(string name) } /// - /// ImportAll Method - /// - /// /// Import all variables of the scope into this scope. - /// + /// public void ImportAll(PyScope scope) { + if (scope is null) throw new ArgumentNullException(nameof(scope)); + int result = Runtime.PyDict_Update(VarsRef, scope.VarsRef); if (result < 0) { @@ -189,13 +181,12 @@ public void ImportAll(PyScope scope) } /// - /// ImportAll Method - /// - /// /// Import all variables of the module into this scope. - /// + /// public void ImportAll(PyObject module) { + if (module is null) throw new ArgumentNullException(nameof(module)); + if (Runtime.PyObject_Type(module.obj) != Runtime.PyModuleType) { throw new PyScopeException("object is not a module"); @@ -209,13 +200,12 @@ public void ImportAll(PyObject module) } /// - /// ImportAll Method - /// - /// /// Import all variables in the dictionary into this scope. - /// + /// public void ImportAll(PyDict dict) { + if (dict is null) throw new ArgumentNullException(nameof(dict)); + int result = Runtime.PyDict_Update(VarsRef, dict.Reference); if (result < 0) { @@ -224,14 +214,13 @@ public void ImportAll(PyDict dict) } /// - /// Execute method - /// - /// /// Execute a Python ast and return the result as a PyObject. /// The ast can be either an expression or stmts. - /// + /// public PyObject Execute(PyObject script, PyDict locals = null) { + if (script is null) throw new ArgumentNullException(nameof(script)); + Check(); IntPtr _locals = locals == null ? variables : locals.obj; IntPtr ptr = Runtime.PyEval_EvalCode(script.Handle, variables, _locals); @@ -245,15 +234,14 @@ public PyObject Execute(PyObject script, PyDict locals = null) } /// - /// Execute method - /// - /// /// Execute a Python ast and return the result as a PyObject, /// and convert the result to a Managed Object of given type. /// The ast can be either an expression or stmts. - /// + /// public T Execute(PyObject script, PyDict locals = null) { + if (script is null) throw new ArgumentNullException(nameof(script)); + Check(); PyObject pyObj = Execute(script, locals); if (pyObj == null) @@ -265,14 +253,13 @@ public T Execute(PyObject script, PyDict locals = null) } /// - /// Eval method - /// - /// /// Evaluate a Python expression and return the result as a PyObject /// or null if an exception is raised. - /// + /// public PyObject Eval(string code, PyDict locals = null) { + if (code is null) throw new ArgumentNullException(nameof(code)); + Check(); BorrowedReference _locals = locals == null ? VarsRef : locals.Reference; @@ -285,13 +272,12 @@ public PyObject Eval(string code, PyDict locals = null) /// /// Evaluate a Python expression + /// and convert the result to a managed object of given type. /// - /// - /// Evaluate a Python expression - /// and convert the result to a Managed Object of given type. - /// public T Eval(string code, PyDict locals = null) { + if (code is null) throw new ArgumentNullException(nameof(code)); + Check(); PyObject pyObj = Eval(code, locals); var obj = pyObj.As(); @@ -306,6 +292,8 @@ public T Eval(string code, PyDict locals = null) /// public void Exec(string code, PyDict locals = null) { + if (code is null) throw new ArgumentNullException(nameof(code)); + Check(); BorrowedReference _locals = locals == null ? VarsRef : locals.Reference; Exec(code, VarsRef, _locals); diff --git a/src/runtime/pysequence.cs b/src/runtime/pysequence.cs index 463c2ec52..b112d6cb2 100644 --- a/src/runtime/pysequence.cs +++ b/src/runtime/pysequence.cs @@ -11,31 +11,23 @@ namespace Python.Runtime /// public class PySequence : PyIterable { - protected internal PySequence(IntPtr ptr) : base(ptr) - { - } - internal PySequence(BorrowedReference reference) : base(reference) { } - internal PySequence(StolenReference reference) : base(reference) { } + internal PySequence(in StolenReference reference) : base(reference) { } /// - /// IsSequenceType Method + /// Returns true if the given object implements the sequence protocol. /// - /// - /// Returns true if the given object implements the sequence protocol. - /// public static bool IsSequenceType(PyObject value) { + if (value is null) throw new ArgumentNullException(nameof(value)); + return Runtime.PySequence_Check(value.obj); } /// - /// GetSlice Method - /// - /// /// Return the slice of the sequence with the given indices. - /// + /// public PyObject GetSlice(int i1, int i2) { IntPtr op = Runtime.PySequence_GetSlice(obj, i1, i2); @@ -48,13 +40,12 @@ public PyObject GetSlice(int i1, int i2) /// - /// SetSlice Method - /// - /// /// Sets the slice of the sequence with the given indices. - /// + /// public void SetSlice(int i1, int i2, PyObject v) { + if (v is null) throw new ArgumentNullException(nameof(v)); + int r = Runtime.PySequence_SetSlice(obj, i1, i2, v.obj); if (r < 0) { @@ -80,14 +71,13 @@ public void DelSlice(int i1, int i2) /// - /// Index Method - /// - /// /// Return the index of the given item in the sequence, or -1 if /// the item does not appear in the sequence. - /// + /// public int Index(PyObject item) { + if (item is null) throw new ArgumentNullException(nameof(item)); + int r = Runtime.PySequence_Index(obj, item.obj); if (r < 0) { @@ -99,14 +89,13 @@ public int Index(PyObject item) /// - /// Contains Method - /// - /// /// Return true if the sequence contains the given item. This method /// throws a PythonException if an error occurs during the check. - /// + /// public bool Contains(PyObject item) { + if (item is null) throw new ArgumentNullException(nameof(item)); + int r = Runtime.PySequence_Contains(obj, item.obj); if (r < 0) { @@ -117,14 +106,13 @@ public bool Contains(PyObject item) /// - /// Concat Method - /// - /// /// Return the concatenation of the sequence object with the passed in /// sequence object. - /// + /// public PyObject Concat(PyObject other) { + if (other is null) throw new ArgumentNullException(nameof(other)); + IntPtr op = Runtime.PySequence_Concat(obj, other.obj); if (op == IntPtr.Zero) { @@ -135,12 +123,9 @@ public PyObject Concat(PyObject other) /// - /// Repeat Method - /// - /// /// Return the sequence object repeated N times. This is equivalent /// to the Python expression "object * count". - /// + /// public PyObject Repeat(int count) { IntPtr op = Runtime.PySequence_Repeat(obj, count); diff --git a/src/runtime/pystring.cs b/src/runtime/pystring.cs index 172c09ebd..4d81decfe 100644 --- a/src/runtime/pystring.cs +++ b/src/runtime/pystring.cs @@ -13,27 +13,18 @@ namespace Python.Runtime /// public class PyString : PySequence { - /// - /// PyString Constructor - /// - /// - /// Creates a new PyString from an existing object reference. Note - /// that the instance assumes ownership of the object reference. - /// The object reference is not checked for type-correctness. - /// - public PyString(IntPtr ptr) : base(ptr) - { - } + internal PyString(in StolenReference reference) : base(reference) { } + internal PyString(BorrowedReference reference) : base(reference) { } - private static IntPtr FromObject(PyObject o) + private static BorrowedReference FromObject(PyObject o) { - if (o == null || !IsStringType(o)) + if (o is null) throw new ArgumentNullException(nameof(o)); + if (!IsStringType(o)) { throw new ArgumentException("object is not a string"); } - Runtime.XIncref(o.obj); - return o.obj; + return o.Reference; } /// @@ -49,11 +40,11 @@ public PyString(PyObject o) : base(FromObject(o)) } - private static IntPtr FromString(string s) + private static NewReference FromString(string s) { IntPtr val = Runtime.PyString_FromString(s); PythonException.ThrowIfIsNull(val); - return val; + return NewReference.DangerousFromPointer(val); } /// /// PyString Constructor @@ -61,7 +52,7 @@ private static IntPtr FromString(string s) /// /// Creates a Python string from a managed string. /// - public PyString(string s) : base(FromString(s)) + public PyString(string s) : base(FromString(s).Steal()) { } diff --git a/src/runtime/pythonengine.cs b/src/runtime/pythonengine.cs index d7322dcc2..011b0c663 100644 --- a/src/runtime/pythonengine.cs +++ b/src/runtime/pythonengine.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; -using System.IO; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; @@ -306,6 +306,8 @@ static void OnProcessExit(object _, EventArgs __) /// CPython interpreter process - this bootstraps the managed runtime /// when it is imported by the CLR extension module. /// + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete(Util.InternalUseOnly)] public static IntPtr InitExt() { try @@ -475,7 +477,7 @@ static void ExecuteShutdownHandlers() /// For more information, see the "Extending and Embedding" section /// of the Python documentation on www.python.org. /// - public static IntPtr AcquireLock() + internal static IntPtr AcquireLock() { return Runtime.PyGILState_Ensure(); } @@ -490,7 +492,7 @@ public static IntPtr AcquireLock() /// For more information, see the "Extending and Embedding" section /// of the Python documentation on www.python.org. /// - public static void ReleaseLock(IntPtr gs) + internal static void ReleaseLock(IntPtr gs) { Runtime.PyGILState_Release(gs); } @@ -527,18 +529,6 @@ public static void EndAllowThreads(IntPtr ts) Runtime.PyEval_RestoreThread(ts); } - [Obsolete("Use PyModule.Import")] - public static PyObject ImportModule(string name) => PyModule.Import(name); - - [Obsolete("Use PyModule.Reload")] - public static PyObject ReloadModule(PyObject module) - => module is PyModule pyModule ? pyModule.Reload() : new PyModule(module).Reload(); - - [Obsolete("Use PyModule.FromString")] - public static PyObject ModuleFromString(string name, string code) - => PyModule.FromString(name, code); - - public static PyObject Compile(string code, string filename = "", RunFlagType mode = RunFlagType.File) { var flag = (int)mode; @@ -643,6 +633,8 @@ public static PyObject RunString(string code, IntPtr? globals = null, IntPtr? lo /// internal static PyObject RunString(string code, BorrowedReference globals, BorrowedReference locals, RunFlagType flag) { + if (code is null) throw new ArgumentNullException(nameof(code)); + NewReference tempGlobals = default; if (globals.IsNull) { @@ -704,6 +696,8 @@ public static PyScope CreateScope() public static PyScope CreateScope(string name) { + if (name is null) throw new ArgumentNullException(nameof(name)); + var scope = PyScopeManager.Global.Create(name); return scope; } @@ -815,6 +809,8 @@ public static void SetArgv(params string[] argv) public static void SetArgv(IEnumerable argv) { + if (argv is null) throw new ArgumentNullException(nameof(argv)); + using (GIL()) { string[] arr = argv.ToArray(); @@ -825,6 +821,9 @@ public static void SetArgv(IEnumerable argv) public static void With(PyObject obj, Action Body) { + if (obj is null) throw new ArgumentNullException(nameof(obj)); + if (Body is null) throw new ArgumentNullException(nameof(Body)); + // Behavior described here: // https://docs.python.org/2/reference/datamodel.html#with-statement-context-managers diff --git a/src/runtime/pythonexception.cs b/src/runtime/pythonexception.cs index f663b3c02..72a40c3da 100644 --- a/src/runtime/pythonexception.cs +++ b/src/runtime/pythonexception.cs @@ -432,7 +432,7 @@ internal static BorrowedReference ThrowIfIsNull(BorrowedReference ob) return ob; } - public static IntPtr ThrowIfIsNull(IntPtr ob) + internal static IntPtr ThrowIfIsNull(IntPtr ob) { if (ob == IntPtr.Zero) { @@ -442,7 +442,7 @@ public static IntPtr ThrowIfIsNull(IntPtr ob) return ob; } - public static void ThrowIfIsNotZero(int value) + internal static void ThrowIfIsNotZero(int value) { if (value != 0) { diff --git a/src/runtime/pytuple.cs b/src/runtime/pytuple.cs index 5a18b6bed..19ba7914d 100644 --- a/src/runtime/pytuple.cs +++ b/src/runtime/pytuple.cs @@ -10,18 +10,7 @@ namespace Python.Runtime /// public class PyTuple : PySequence { - /// - /// PyTuple Constructor - /// - /// - /// Creates a new PyTuple from an existing object reference. Note - /// that the instance assumes ownership of the object reference. - /// The object reference is not checked for type-correctness. - /// - public PyTuple(IntPtr ptr) : base(ptr) - { - } - + internal PyTuple(in StolenReference reference) : base(reference) { } /// /// PyTuple Constructor /// @@ -31,14 +20,15 @@ public PyTuple(IntPtr ptr) : base(ptr) /// internal PyTuple(BorrowedReference reference) : base(reference) { } - private static IntPtr FromObject(PyObject o) + private static BorrowedReference FromObject(PyObject o) { - if (o == null || !IsTupleType(o)) + if (o is null) throw new ArgumentNullException(nameof(o)); + + if (!IsTupleType(o)) { throw new ArgumentException("object is not a tuple"); } - Runtime.XIncref(o.obj); - return o.obj; + return o.Reference; } /// @@ -60,13 +50,19 @@ public PyTuple(PyObject o) : base(FromObject(o)) /// /// Creates a new empty PyTuple. /// - public PyTuple() : base(Runtime.PyTuple_New(0)) + public PyTuple() : base(NewEmtpy().Steal()) { } + + private static NewReference NewEmtpy() { - PythonException.ThrowIfIsNull(obj); + IntPtr ptr = Runtime.PyTuple_New(0); + PythonException.ThrowIfIsNull(ptr); + return NewReference.DangerousFromPointer(ptr); } - private static IntPtr FromArray(PyObject[] items) + private static NewReference FromArray(PyObject[] items) { + if (items is null) throw new ArgumentNullException(nameof(items)); + int count = items.Length; IntPtr val = Runtime.PyTuple_New(count); for (var i = 0; i < count; i++) @@ -80,7 +76,7 @@ private static IntPtr FromArray(PyObject[] items) throw PythonException.ThrowLastAsClrException(); } } - return val; + return NewReference.DangerousFromPointer(val); } /// @@ -92,36 +88,34 @@ private static IntPtr FromArray(PyObject[] items) /// See caveats about PyTuple_SetItem: /// https://www.coursehero.com/file/p4j2ogg/important-exceptions-to-this-rule-PyTupleSetItem-and-PyListSetItem-These/ /// - public PyTuple(PyObject[] items) : base(FromArray(items)) + public PyTuple(PyObject[] items) : base(FromArray(items).Steal()) { } /// - /// IsTupleType Method + /// Returns true if the given object is a Python tuple. /// - /// - /// Returns true if the given object is a Python tuple. - /// public static bool IsTupleType(PyObject value) { + if (value is null) throw new ArgumentNullException(nameof(value)); + return Runtime.PyTuple_Check(value.obj); } /// - /// AsTuple Method + /// Convert a Python object to a Python tuple if possible. This is + /// equivalent to the Python expression "tuple()". /// - /// - /// Convert a Python object to a Python tuple if possible, raising - /// a PythonException if the conversion is not possible. This is - /// equivalent to the Python expression "tuple(object)". - /// + /// Raised if the object can not be converted to a tuple. public static PyTuple AsTuple(PyObject value) { - IntPtr op = Runtime.PySequence_Tuple(value.obj); + if (value is null) throw new ArgumentNullException(nameof(value)); + + NewReference op = Runtime.PySequence_Tuple(value.Reference); PythonException.ThrowIfIsNull(op); - return new PyTuple(op); + return new PyTuple(op.Steal()); } } } diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index 318c7b794..60d57ea9c 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -83,13 +83,11 @@ internal static Version PyVersion { get { - using (var versionTuple = new PyTuple(PySys_GetObject("version_info"))) - { - var major = Converter.ToInt32(versionTuple[0].Reference); - var minor = Converter.ToInt32(versionTuple[1].Reference); - var micro = Converter.ToInt32(versionTuple[2].Reference); - return new Version(major, minor, micro); - } + var versionTuple = PySys_GetObject("version_info"); + var major = Converter.ToInt32(PyTuple_GetItem(versionTuple, 0)); + var minor = Converter.ToInt32(PyTuple_GetItem(versionTuple, 1)); + var micro = Converter.ToInt32(PyTuple_GetItem(versionTuple, 2)); + return new Version(major, minor, micro); } } @@ -144,8 +142,7 @@ internal static void Initialize(bool initSigs = false, ShutdownMode mode = Shutd InitPyMembers(); - ABI.Initialize(PyVersion, - pyType: new BorrowedReference(PyTypeType)); + ABI.Initialize(PyVersion); GenericUtil.Reset(); PyScopeManager.Reset(); @@ -258,11 +255,6 @@ private static void InitPyMembers() XDecref(op); op = PyInt_FromInt32(0); - SetPyMemberTypeOf(ref PyIntType, op, - () => PyIntType = IntPtr.Zero); - XDecref(op); - - op = PyLong_FromLong(0); SetPyMemberTypeOf(ref PyLongType, op, () => PyLongType = IntPtr.Zero); XDecref(op); @@ -556,7 +548,6 @@ private static void MoveClrInstancesOnwershipToPython() internal static IntPtr PyTupleType; internal static IntPtr PyListType; internal static IntPtr PyDictType; - internal static IntPtr PyIntType; internal static IntPtr PyLongType; internal static IntPtr PyFloatType; internal static IntPtr PyBoolType; @@ -740,6 +731,7 @@ internal static unsafe void XDecref(IntPtr op) { #if DEBUG Debug.Assert(op == IntPtr.Zero || Refcount(op) > 0); + Debug.Assert(_isInitialized || Py_IsInitialized() != 0); #endif #if !CUSTOM_INCDEC_REF Py_DecRef(op); @@ -1095,7 +1087,7 @@ internal static IntPtr PyObject_GetAttr(IntPtr pointer, IntPtr name) internal static int PyObject_DelItem(IntPtr pointer, IntPtr key) => Delegates.PyObject_DelItem(pointer, key); - internal static IntPtr PyObject_GetIter(IntPtr op) => Delegates.PyObject_GetIter(op); + internal static NewReference PyObject_GetIter(BorrowedReference op) => Delegates.PyObject_GetIter(op); internal static IntPtr PyObject_Call(IntPtr pointer, IntPtr args, IntPtr kw) => Delegates.PyObject_Call(pointer, args, kw); @@ -1230,22 +1222,19 @@ internal static IntPtr PyBuffer_SizeFromFormat(string format) //==================================================================== - internal static IntPtr PyNumber_Int(IntPtr ob) => Delegates.PyNumber_Int(ob); - - - internal static IntPtr PyNumber_Long(IntPtr ob) => Delegates.PyNumber_Long(ob); + internal static NewReference PyNumber_Long(BorrowedReference ob) => Delegates.PyNumber_Long(ob); - internal static IntPtr PyNumber_Float(IntPtr ob) => Delegates.PyNumber_Float(ob); + internal static NewReference PyNumber_Float(BorrowedReference ob) => Delegates.PyNumber_Float(ob); internal static bool PyNumber_Check(IntPtr ob) => Delegates.PyNumber_Check(ob); internal static bool PyInt_Check(BorrowedReference ob) - => PyObject_TypeCheck(ob, new BorrowedReference(PyIntType)); + => PyObject_TypeCheck(ob, new BorrowedReference(PyLongType)); internal static bool PyInt_Check(IntPtr ob) { - return PyObject_TypeCheck(ob, PyIntType); + return PyObject_TypeCheck(ob, PyLongType); } internal static bool PyBool_Check(IntPtr ob) @@ -1254,60 +1243,28 @@ internal static bool PyBool_Check(IntPtr ob) } internal static IntPtr PyInt_FromInt32(int value) - { - var v = new IntPtr(value); - return PyInt_FromLong(v); - } - - internal static IntPtr PyInt_FromInt64(long value) - { - var v = new IntPtr(value); - return PyInt_FromLong(v); - } - - - private static IntPtr PyInt_FromLong(IntPtr value) => Delegates.PyInt_FromLong(value); - - - internal static int PyInt_AsLong(IntPtr value) => Delegates.PyInt_AsLong(value); + => PyLong_FromLongLong(value).DangerousMoveToPointerOrNull(); + internal static NewReference PyInt_FromInt64(long value) => PyLong_FromLongLong(value); internal static bool PyLong_Check(IntPtr ob) { return PyObject_TYPE(ob) == PyLongType; } - - internal static IntPtr PyLong_FromLong(long value) => Delegates.PyLong_FromLong(value); - - - internal static IntPtr PyLong_FromUnsignedLong32(uint value) => Delegates.PyLong_FromUnsignedLong32(value); - - - internal static IntPtr PyLong_FromUnsignedLong64(ulong value) => Delegates.PyLong_FromUnsignedLong64(value); - - internal static IntPtr PyLong_FromUnsignedLong(object value) - { - if (Is32Bit || IsWindows) - return PyLong_FromUnsignedLong32(Convert.ToUInt32(value)); - else - return PyLong_FromUnsignedLong64(Convert.ToUInt64(value)); - } - - internal static IntPtr PyLong_FromDouble(double value) => Delegates.PyLong_FromDouble(value); - internal static IntPtr PyLong_FromLongLong(long value) => Delegates.PyLong_FromLongLong(value); + internal static NewReference PyLong_FromLongLong(long value) => Delegates.PyLong_FromLongLong(value); - internal static IntPtr PyLong_FromUnsignedLongLong(ulong value) => Delegates.PyLong_FromUnsignedLongLong(value); + internal static NewReference PyLong_FromUnsignedLongLong(ulong value) => Delegates.PyLong_FromUnsignedLongLong(value); - internal static IntPtr PyLong_FromString(string value, IntPtr end, int radix) + internal static NewReference PyLong_FromString(string value, int radix) { using var valPtr = new StrPtr(value, Encoding.UTF8); - return Delegates.PyLong_FromString(valPtr, end, radix); + return Delegates.PyLong_FromString(valPtr, IntPtr.Zero, radix); } @@ -1318,18 +1275,25 @@ internal static IntPtr PyLong_FromString(string value, IntPtr end, int radix) internal static nint PyLong_AsSignedSize_t(BorrowedReference value) => Delegates.PyLong_AsSignedSize_t(value); - /// - /// This function is a rename of PyLong_AsLongLong, which has a commonly undesired - /// behavior to convert everything (including floats) to integer type, before returning - /// the value as . - /// - /// In most cases you need to check that value is an instance of PyLongObject - /// before using this function using . - /// - - internal static long PyExplicitlyConvertToInt64(IntPtr value) => Delegates.PyExplicitlyConvertToInt64(value); + internal static long? PyLong_AsLongLong(IntPtr value) + { + long result = Delegates.PyLong_AsLongLong(value); + if (result == -1 && Exceptions.ErrorOccurred()) + { + return null; + } + return result; + } - internal static ulong PyLong_AsUnsignedLongLong(IntPtr value) => Delegates.PyLong_AsUnsignedLongLong(value); + internal static ulong? PyLong_AsUnsignedLongLong(IntPtr value) + { + ulong result = Delegates.PyLong_AsUnsignedLongLong(value); + if (result == unchecked((ulong)-1) && Exceptions.ErrorOccurred()) + { + return null; + } + return result; + } internal static bool PyFloat_Check(IntPtr ob) { @@ -1512,10 +1476,10 @@ internal static long PySequence_Count(IntPtr pointer, IntPtr value) private static IntPtr _PySequence_Count(IntPtr pointer, IntPtr value) => Delegates._PySequence_Count(pointer, value); - internal static IntPtr PySequence_Tuple(IntPtr pointer) => Delegates.PySequence_Tuple(pointer); + internal static NewReference PySequence_Tuple(BorrowedReference pointer) => Delegates.PySequence_Tuple(pointer); - internal static IntPtr PySequence_List(IntPtr pointer) => Delegates.PySequence_List(pointer); + internal static NewReference PySequence_List(BorrowedReference pointer) => Delegates.PySequence_List(pointer); //==================================================================== @@ -1738,7 +1702,7 @@ internal static IntPtr PyDict_Keys(IntPtr pointer) internal static NewReference PyDict_Items(BorrowedReference pointer) => Delegates.PyDict_Items(pointer); - internal static IntPtr PyDict_Copy(IntPtr pointer) => Delegates.PyDict_Copy(pointer); + internal static NewReference PyDict_Copy(BorrowedReference pointer) => Delegates.PyDict_Copy(pointer); internal static int PyDict_Update(BorrowedReference pointer, BorrowedReference other) => Delegates.PyDict_Update(pointer, other); @@ -1902,16 +1866,14 @@ 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) + internal static bool PyIter_Check(BorrowedReference ob) { - var ob_type = PyObject_TYPE(pointer); - IntPtr tp_iternext = Marshal.ReadIntPtr(ob_type, TypeOffset.tp_iternext); + if (Delegates.PyIter_Check != null) + return Delegates.PyIter_Check(ob) != 0; + var ob_type = PyObject_TYPE(ob); + IntPtr tp_iternext = Marshal.ReadIntPtr(ob_type.DangerousGetAddress(), TypeOffset.tp_iternext); return tp_iternext != IntPtr.Zero && tp_iternext != _PyObject_NextNotImplemented; } - - internal static IntPtr PyIter_Next(IntPtr pointer) => Delegates.PyIter_Next(new BorrowedReference(pointer)).DangerousMoveToPointerOrNull(); internal static NewReference PyIter_Next(BorrowedReference pointer) => Delegates.PyIter_Next(pointer); @@ -2380,7 +2342,7 @@ static Delegates() PyObject_GetItem = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_GetItem), GetUnmanagedDll(_PythonDll)); PyObject_SetItem = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_SetItem), GetUnmanagedDll(_PythonDll)); PyObject_DelItem = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_DelItem), GetUnmanagedDll(_PythonDll)); - PyObject_GetIter = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_GetIter), 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_RichCompareBool = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_RichCompareBool), GetUnmanagedDll(_PythonDll)); @@ -2411,23 +2373,14 @@ static Delegates() PyBuffer_ToContiguous = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyBuffer_ToContiguous), GetUnmanagedDll(_PythonDll)); PyBuffer_FillContiguousStrides = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyBuffer_FillContiguousStrides), GetUnmanagedDll(_PythonDll)); PyBuffer_FillInfo = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyBuffer_FillInfo), GetUnmanagedDll(_PythonDll)); - PyNumber_Int = (delegate* unmanaged[Cdecl])GetFunctionByName("PyNumber_Long", GetUnmanagedDll(_PythonDll)); - PyNumber_Long = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyNumber_Long), GetUnmanagedDll(_PythonDll)); - PyNumber_Float = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyNumber_Float), GetUnmanagedDll(_PythonDll)); + PyNumber_Long = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyNumber_Long), GetUnmanagedDll(_PythonDll)); + PyNumber_Float = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyNumber_Float), GetUnmanagedDll(_PythonDll)); PyNumber_Check = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyNumber_Check), GetUnmanagedDll(_PythonDll)); - PyInt_FromLong = (delegate* unmanaged[Cdecl])GetFunctionByName("PyLong_FromLong", GetUnmanagedDll(_PythonDll)); - PyInt_AsLong = (delegate* unmanaged[Cdecl])GetFunctionByName("PyLong_AsLong", GetUnmanagedDll(_PythonDll)); - PyLong_FromLong = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyLong_FromLong), GetUnmanagedDll(_PythonDll)); - PyLong_FromUnsignedLong32 = (delegate* unmanaged[Cdecl])GetFunctionByName("PyLong_FromUnsignedLong", GetUnmanagedDll(_PythonDll)); - PyLong_FromUnsignedLong64 = (delegate* unmanaged[Cdecl])GetFunctionByName("PyLong_FromUnsignedLong", GetUnmanagedDll(_PythonDll)); PyLong_FromDouble = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyLong_FromDouble), GetUnmanagedDll(_PythonDll)); - PyLong_FromLongLong = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyLong_FromLongLong), GetUnmanagedDll(_PythonDll)); - PyLong_FromUnsignedLongLong = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyLong_FromUnsignedLongLong), GetUnmanagedDll(_PythonDll)); - PyLong_FromString = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyLong_FromString), GetUnmanagedDll(_PythonDll)); - PyLong_AsLong = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyLong_AsLong), GetUnmanagedDll(_PythonDll)); - PyLong_AsUnsignedLong32 = (delegate* unmanaged[Cdecl])GetFunctionByName("PyLong_AsUnsignedLong", GetUnmanagedDll(_PythonDll)); - PyLong_AsUnsignedLong64 = (delegate* unmanaged[Cdecl])GetFunctionByName("PyLong_AsUnsignedLong", GetUnmanagedDll(_PythonDll)); - PyLong_AsLongLong = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyLong_AsLongLong), GetUnmanagedDll(_PythonDll)); + PyLong_FromLongLong = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyLong_FromLongLong), GetUnmanagedDll(_PythonDll)); + PyLong_FromUnsignedLongLong = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyLong_FromUnsignedLongLong), GetUnmanagedDll(_PythonDll)); + PyLong_FromString = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyLong_FromString), GetUnmanagedDll(_PythonDll)); + PyLong_AsLongLong = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyLong_AsLongLong), GetUnmanagedDll(_PythonDll)); PyLong_AsUnsignedLongLong = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyLong_AsUnsignedLongLong), GetUnmanagedDll(_PythonDll)); PyLong_FromVoidPtr = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyLong_FromVoidPtr), GetUnmanagedDll(_PythonDll)); PyLong_AsVoidPtr = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyLong_AsVoidPtr), GetUnmanagedDll(_PythonDll)); @@ -2472,8 +2425,8 @@ static Delegates() PySequence_Repeat = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PySequence_Repeat), GetUnmanagedDll(_PythonDll)); PySequence_Index = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PySequence_Index), GetUnmanagedDll(_PythonDll)); _PySequence_Count = (delegate* unmanaged[Cdecl])GetFunctionByName("PySequence_Count", GetUnmanagedDll(_PythonDll)); - PySequence_Tuple = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PySequence_Tuple), GetUnmanagedDll(_PythonDll)); - PySequence_List = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PySequence_List), GetUnmanagedDll(_PythonDll)); + PySequence_Tuple = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PySequence_Tuple), GetUnmanagedDll(_PythonDll)); + PySequence_List = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PySequence_List), GetUnmanagedDll(_PythonDll)); PyBytes_AsString = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyBytes_AsString), GetUnmanagedDll(_PythonDll)); PyBytes_FromString = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyBytes_FromString), GetUnmanagedDll(_PythonDll)); _PyBytes_Size = (delegate* unmanaged[Cdecl])GetFunctionByName("PyBytes_Size", GetUnmanagedDll(_PythonDll)); @@ -2500,7 +2453,7 @@ static Delegates() PyDict_Keys = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyDict_Keys), GetUnmanagedDll(_PythonDll)); PyDict_Values = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyDict_Values), GetUnmanagedDll(_PythonDll)); PyDict_Items = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyDict_Items), GetUnmanagedDll(_PythonDll)); - PyDict_Copy = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyDict_Copy), GetUnmanagedDll(_PythonDll)); + PyDict_Copy = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyDict_Copy), GetUnmanagedDll(_PythonDll)); PyDict_Update = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyDict_Update), GetUnmanagedDll(_PythonDll)); PyDict_Clear = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyDict_Clear), GetUnmanagedDll(_PythonDll)); _PyDict_Size = (delegate* unmanaged[Cdecl])GetFunctionByName("PyDict_Size", GetUnmanagedDll(_PythonDll)); @@ -2523,6 +2476,10 @@ static Delegates() PyTuple_SetItem = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyTuple_SetItem), GetUnmanagedDll(_PythonDll)); PyTuple_GetSlice = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyTuple_GetSlice), GetUnmanagedDll(_PythonDll)); PyTuple_Size = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyTuple_Size), GetUnmanagedDll(_PythonDll)); + try + { + PyIter_Check = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyIter_Check), GetUnmanagedDll(_PythonDll)); + } catch (MissingMethodException) { } PyIter_Next = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyIter_Next), GetUnmanagedDll(_PythonDll)); PyModule_New = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyModule_New), GetUnmanagedDll(_PythonDll)); PyModule_GetName = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyModule_GetName), GetUnmanagedDll(_PythonDll)); @@ -2585,7 +2542,6 @@ static Delegates() Py_MakePendingCalls = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(Py_MakePendingCalls), GetUnmanagedDll(_PythonDll)); PyLong_AsUnsignedSize_t = (delegate* unmanaged[Cdecl])GetFunctionByName("PyLong_AsSize_t", GetUnmanagedDll(_PythonDll)); PyLong_AsSignedSize_t = (delegate* unmanaged[Cdecl])GetFunctionByName("PyLong_AsSsize_t", GetUnmanagedDll(_PythonDll)); - PyExplicitlyConvertToInt64 = (delegate* unmanaged[Cdecl])GetFunctionByName("PyLong_AsLongLong", GetUnmanagedDll(_PythonDll)); PyDict_GetItemWithError = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyDict_GetItemWithError), GetUnmanagedDll(_PythonDll)); PyException_GetCause = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyException_GetCause), GetUnmanagedDll(_PythonDll)); PyException_GetTraceback = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyException_GetTraceback), GetUnmanagedDll(_PythonDll)); @@ -2684,7 +2640,7 @@ static Delegates() internal static delegate* unmanaged[Cdecl] PyObject_GetItem { get; } internal static delegate* unmanaged[Cdecl] PyObject_SetItem { get; } internal static delegate* unmanaged[Cdecl] PyObject_DelItem { get; } - internal static delegate* unmanaged[Cdecl] PyObject_GetIter { 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_RichCompareBool { get; } @@ -2708,23 +2664,14 @@ static Delegates() internal static delegate* unmanaged[Cdecl] PyBuffer_ToContiguous { get; } internal static delegate* unmanaged[Cdecl] PyBuffer_FillContiguousStrides { get; } internal static delegate* unmanaged[Cdecl] PyBuffer_FillInfo { get; } - internal static delegate* unmanaged[Cdecl] PyNumber_Int { get; } - internal static delegate* unmanaged[Cdecl] PyNumber_Long { get; } - internal static delegate* unmanaged[Cdecl] PyNumber_Float { get; } + internal static delegate* unmanaged[Cdecl] PyNumber_Long { get; } + internal static delegate* unmanaged[Cdecl] PyNumber_Float { get; } internal static delegate* unmanaged[Cdecl] PyNumber_Check { get; } - internal static delegate* unmanaged[Cdecl] PyInt_FromLong { get; } - internal static delegate* unmanaged[Cdecl] PyInt_AsLong { get; } - internal static delegate* unmanaged[Cdecl] PyLong_FromLong { get; } - internal static delegate* unmanaged[Cdecl] PyLong_FromUnsignedLong32 { get; } - internal static delegate* unmanaged[Cdecl] PyLong_FromUnsignedLong64 { get; } internal static delegate* unmanaged[Cdecl] PyLong_FromDouble { get; } - internal static delegate* unmanaged[Cdecl] PyLong_FromLongLong { get; } - internal static delegate* unmanaged[Cdecl] PyLong_FromUnsignedLongLong { get; } - internal static delegate* unmanaged[Cdecl] PyLong_FromString { get; } - internal static delegate* unmanaged[Cdecl] PyLong_AsLong { get; } - internal static delegate* unmanaged[Cdecl] PyLong_AsUnsignedLong32 { get; } - internal static delegate* unmanaged[Cdecl] PyLong_AsUnsignedLong64 { get; } - internal static delegate* unmanaged[Cdecl] PyLong_AsLongLong { get; } + internal static delegate* unmanaged[Cdecl] PyLong_FromLongLong { get; } + internal static delegate* unmanaged[Cdecl] PyLong_FromUnsignedLongLong { get; } + internal static delegate* unmanaged[Cdecl] PyLong_FromString { get; } + internal static delegate* unmanaged[Cdecl] PyLong_AsLongLong { get; } internal static delegate* unmanaged[Cdecl] PyLong_AsUnsignedLongLong { get; } internal static delegate* unmanaged[Cdecl] PyLong_FromVoidPtr { get; } internal static delegate* unmanaged[Cdecl] PyLong_AsVoidPtr { get; } @@ -2769,8 +2716,8 @@ static Delegates() internal static delegate* unmanaged[Cdecl] PySequence_Repeat { get; } internal static delegate* unmanaged[Cdecl] PySequence_Index { get; } internal static delegate* unmanaged[Cdecl] _PySequence_Count { get; } - internal static delegate* unmanaged[Cdecl] PySequence_Tuple { get; } - internal static delegate* unmanaged[Cdecl] PySequence_List { get; } + internal static delegate* unmanaged[Cdecl] PySequence_Tuple { get; } + internal static delegate* unmanaged[Cdecl] PySequence_List { get; } internal static delegate* unmanaged[Cdecl] PyBytes_AsString { get; } internal static delegate* unmanaged[Cdecl] PyBytes_FromString { get; } internal static delegate* unmanaged[Cdecl] _PyBytes_Size { get; } @@ -2797,7 +2744,7 @@ static Delegates() internal static delegate* unmanaged[Cdecl] PyDict_Keys { get; } internal static delegate* unmanaged[Cdecl] PyDict_Values { get; } internal static delegate* unmanaged[Cdecl] PyDict_Items { get; } - internal static delegate* unmanaged[Cdecl] PyDict_Copy { get; } + internal static delegate* unmanaged[Cdecl] PyDict_Copy { get; } internal static delegate* unmanaged[Cdecl] PyDict_Update { get; } internal static delegate* unmanaged[Cdecl] PyDict_Clear { get; } internal static delegate* unmanaged[Cdecl] _PyDict_Size { get; } @@ -2820,6 +2767,7 @@ static Delegates() internal static delegate* unmanaged[Cdecl] PyTuple_SetItem { get; } internal static delegate* unmanaged[Cdecl] PyTuple_GetSlice { get; } internal static delegate* unmanaged[Cdecl] PyTuple_Size { get; } + internal static delegate* unmanaged[Cdecl] PyIter_Check { get; } internal static delegate* unmanaged[Cdecl] PyIter_Next { get; } internal static delegate* unmanaged[Cdecl] PyModule_New { get; } internal static delegate* unmanaged[Cdecl] PyModule_GetName { get; } @@ -2874,7 +2822,6 @@ static Delegates() internal static delegate* unmanaged[Cdecl] Py_MakePendingCalls { get; } internal static delegate* unmanaged[Cdecl] PyLong_AsUnsignedSize_t { get; } internal static delegate* unmanaged[Cdecl] PyLong_AsSignedSize_t { get; } - internal static delegate* unmanaged[Cdecl] PyExplicitlyConvertToInt64 { get; } internal static delegate* unmanaged[Cdecl] PyDict_GetItemWithError { get; } internal static delegate* unmanaged[Cdecl] PyException_GetCause { get; } internal static delegate* unmanaged[Cdecl] PyException_GetTraceback { get; } diff --git a/src/testing/threadtest.cs b/src/testing/threadtest.cs index 6664c3643..3c137df4e 100644 --- a/src/testing/threadtest.cs +++ b/src/testing/threadtest.cs @@ -29,8 +29,7 @@ public class ThreadTest /// public static string CallEchoString(string arg) { - IntPtr gs = PythonEngine.AcquireLock(); - try + using (Py.GIL()) { if (module == null) { @@ -45,16 +44,11 @@ public static string CallEchoString(string arg) temp.Dispose(); return result; } - finally - { - PythonEngine.ReleaseLock(gs); - } } public static string CallEchoString2(string arg) { - IntPtr gs = PythonEngine.AcquireLock(); - try + using (Py.GIL()) { if (module == null) { @@ -70,10 +64,6 @@ public static string CallEchoString2(string arg) temp.Dispose(); return result; } - finally - { - PythonEngine.ReleaseLock(gs); - } } } } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy