From 392537ae521e1e8a37955a81160c43f8c458df23 Mon Sep 17 00:00:00 2001 From: Victor Nova Date: Tue, 14 Sep 2021 17:11:10 -0700 Subject: [PATCH] cleaning up public API --- src/embed_tests/TestConverter.cs | 2 +- src/embed_tests/TestFinalizer.cs | 8 +- src/embed_tests/TestPyAnsiString.cs | 97 ------- src/embed_tests/TestPyFloat.cs | 9 - src/embed_tests/TestPyInt.cs | 14 +- src/embed_tests/TestPyLong.cs | 208 --------------- src/embed_tests/TestPyString.cs | 5 +- src/embed_tests/TestRuntime.cs | 28 +- .../{EnumPyLongCodec.cs => EnumPyIntCodec.cs} | 12 +- src/runtime/Codecs/TupleCodecs.cs | 2 +- .../CollectionWrappers/IterableWrapper.cs | 8 +- src/runtime/Util.cs | 2 + src/runtime/arrayobject.cs | 44 ++-- src/runtime/classderived.cs | 21 +- src/runtime/converter.cs | 43 ++- src/runtime/delegatemanager.cs | 4 +- src/runtime/finalizer.cs | 69 +++-- src/runtime/metatype.cs | 6 +- src/runtime/native/ABI.cs | 2 +- src/runtime/pyansistring.cs | 71 ----- src/runtime/pybuffer.cs | 10 +- src/runtime/pydict.cs | 41 +-- src/runtime/pyfloat.cs | 43 ++- src/runtime/pyint.cs | 80 +++--- src/runtime/pyiter.cs | 15 +- src/runtime/pylist.cs | 85 +++--- src/runtime/pylong.cs | 249 ------------------ src/runtime/pynumber.cs | 9 +- src/runtime/pyobject.cs | 34 +-- src/runtime/pyscope.cs | 74 +++--- src/runtime/pysequence.cs | 51 ++-- src/runtime/pystring.cs | 27 +- src/runtime/pythonengine.cs | 29 +- src/runtime/pythonexception.cs | 4 +- src/runtime/pytuple.cs | 60 ++--- src/runtime/runtime.cs | 191 +++++--------- src/testing/threadtest.cs | 14 +- 37 files changed, 451 insertions(+), 1220 deletions(-) delete mode 100644 src/embed_tests/TestPyAnsiString.cs delete mode 100644 src/embed_tests/TestPyLong.cs rename src/runtime/Codecs/{EnumPyLongCodec.cs => EnumPyIntCodec.cs} (80%) delete mode 100644 src/runtime/pyansistring.cs delete mode 100644 src/runtime/pylong.cs 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); - } } } }