diff --git a/CHANGELOG.md b/CHANGELOG.md index db73bb629..8ba1594ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. - `clr.AddReference` may now throw errors besides `FileNotFoundException`, that provide more details about the cause of the failure - `clr.AddReference` no longer adds ".dll" implicitly +- `PyIter(PyObject)` constructor replaced with static `PyIter.GetIter(PyObject)` method ### Fixed diff --git a/src/runtime/pyansistring.cs b/src/runtime/pyansistring.cs index 185cc6c94..8a27104b1 100644 --- a/src/runtime/pyansistring.cs +++ b/src/runtime/pyansistring.cs @@ -17,6 +17,16 @@ 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 /// @@ -25,14 +35,14 @@ public PyAnsiString(IntPtr ptr) : base(ptr) /// An ArgumentException will be thrown if the given object is not /// a Python string object. /// - public PyAnsiString(PyObject o) + public PyAnsiString(PyObject o) : base(FromObject(o)) { - if (!IsStringType(o)) - { - throw new ArgumentException("object is not a string"); - } - Runtime.XIncref(o.obj); - obj = o.obj; + } + private static IntPtr FromString(string s) + { + IntPtr val = Runtime.PyString_FromString(s); + PythonException.ThrowIfIsNull(val); + return val; } @@ -42,10 +52,8 @@ public PyAnsiString(PyObject o) /// /// Creates a Python string from a managed string. /// - public PyAnsiString(string s) + public PyAnsiString(string s) : base(FromString(s)) { - obj = Runtime.PyString_FromString(s); - PythonException.ThrowIfIsNull(obj); } diff --git a/src/runtime/pydict.cs b/src/runtime/pydict.cs index 7ff7a83c8..ade873f7a 100644 --- a/src/runtime/pydict.cs +++ b/src/runtime/pydict.cs @@ -29,9 +29,8 @@ public PyDict(IntPtr ptr) : base(ptr) /// /// Creates a new Python dictionary object. /// - public PyDict() + public PyDict() : base(Runtime.PyDict_New()) { - obj = Runtime.PyDict_New(); if (obj == IntPtr.Zero) { throw new PythonException(); @@ -47,14 +46,13 @@ public PyDict() /// ArgumentException will be thrown if the given object is not a /// Python dictionary object. /// - public PyDict(PyObject o) + public PyDict(PyObject o) : base(o.obj) { + Runtime.XIncref(o.obj); if (!IsDictType(o)) { throw new ArgumentException("object is not a dict"); } - Runtime.XIncref(o.obj); - obj = o.obj; } diff --git a/src/runtime/pyfloat.cs b/src/runtime/pyfloat.cs index d6fb55f26..b07b95de1 100644 --- a/src/runtime/pyfloat.cs +++ b/src/runtime/pyfloat.cs @@ -4,7 +4,6 @@ namespace Python.Runtime { /// /// Represents a Python float object. See the documentation at - /// PY2: https://docs.python.org/2/c-api/float.html /// PY3: https://docs.python.org/3/c-api/float.html /// for details. /// @@ -31,14 +30,8 @@ public PyFloat(IntPtr ptr) : base(ptr) /// ArgumentException will be thrown if the given object is not a /// Python float object. /// - public PyFloat(PyObject o) + public PyFloat(PyObject o) : base(FromObject(o)) { - if (!IsFloatType(o)) - { - throw new ArgumentException("object is not a float"); - } - Runtime.XIncref(o.obj); - obj = o.obj; } @@ -48,12 +41,36 @@ public PyFloat(PyObject o) /// /// Creates a new Python float from a double value. /// - public PyFloat(double value) + public PyFloat(double value) : base(FromDouble(value)) + { + } + + private static IntPtr FromObject(PyObject o) + { + if (o == null || !IsFloatType(o)) + { + throw new ArgumentException("object is not a float"); + } + Runtime.XIncref(o.obj); + return o.obj; + } + + private static IntPtr FromDouble(double value) { - obj = Runtime.PyFloat_FromDouble(value); - PythonException.ThrowIfIsNull(obj); + IntPtr val = Runtime.PyFloat_FromDouble(value); + PythonException.ThrowIfIsNull(val); + return val; } + private static IntPtr FromString(string value) + { + using (var s = new PyString(value)) + { + IntPtr val = Runtime.PyFloat_FromString(s.obj, IntPtr.Zero); + PythonException.ThrowIfIsNull(val); + return val; + } + } /// /// PyFloat Constructor @@ -61,13 +78,8 @@ public PyFloat(double value) /// /// Creates a new Python float from a string value. /// - public PyFloat(string value) + public PyFloat(string value) : base(FromString(value)) { - using (var s = new PyString(value)) - { - obj = Runtime.PyFloat_FromString(s.obj, IntPtr.Zero); - PythonException.ThrowIfIsNull(obj); - } } diff --git a/src/runtime/pyint.cs b/src/runtime/pyint.cs index 31295c899..e49e62a8a 100644 --- a/src/runtime/pyint.cs +++ b/src/runtime/pyint.cs @@ -31,16 +31,26 @@ public PyInt(IntPtr ptr) : base(ptr) /// ArgumentException will be thrown if the given object is not a /// Python int object. /// - public PyInt(PyObject o) + public PyInt(PyObject o) : base(FromObject(o)) { - if (!IsIntType(o)) + } + + private static IntPtr FromObject(PyObject o) + { + if (o == null || !IsIntType(o)) { throw new ArgumentException("object is not an int"); } Runtime.XIncref(o.obj); - obj = o.obj; + return o.obj; } + private static IntPtr FromInt(int value) + { + IntPtr val = Runtime.PyInt_FromInt32(value); + PythonException.ThrowIfIsNull(val); + return val; + } /// /// PyInt Constructor @@ -48,10 +58,8 @@ public PyInt(PyObject o) /// /// Creates a new Python int from an int32 value. /// - public PyInt(int value) + public PyInt(int value) : base(FromInt(value)) { - obj = Runtime.PyInt_FromInt32(value); - PythonException.ThrowIfIsNull(obj); } @@ -62,10 +70,8 @@ public PyInt(int value) /// Creates a new Python int from a uint32 value. /// [CLSCompliant(false)] - public PyInt(uint value) + public PyInt(uint value) : base(FromLong(value)) { - obj = Runtime.PyInt_FromInt64(value); - PythonException.ThrowIfIsNull(obj); } @@ -75,10 +81,15 @@ public PyInt(uint value) /// /// Creates a new Python int from an int64 value. /// - public PyInt(long value) + public PyInt(long value) : base(FromLong(value)) { - obj = Runtime.PyInt_FromInt64(value); - PythonException.ThrowIfIsNull(obj); + } + + private static IntPtr FromLong(long value) + { + IntPtr val = Runtime.PyInt_FromInt64(value); + PythonException.ThrowIfIsNull(val); + return val; } @@ -89,10 +100,8 @@ public PyInt(long value) /// Creates a new Python int from a uint64 value. /// [CLSCompliant(false)] - public PyInt(ulong value) + public PyInt(ulong value) : base(FromLong((long)value)) { - obj = Runtime.PyInt_FromInt64((long)value); - PythonException.ThrowIfIsNull(obj); } @@ -142,16 +151,21 @@ public PyInt(sbyte value) : this((int)value) } + private static IntPtr FromString(string value) + { + IntPtr val = Runtime.PyInt_FromString(value, IntPtr.Zero, 0); + PythonException.ThrowIfIsNull(val); + return val; + } + /// /// PyInt Constructor /// /// /// Creates a new Python int from a string value. /// - public PyInt(string value) + public PyInt(string value) : base(FromString(value)) { - obj = Runtime.PyInt_FromString(value, IntPtr.Zero, 0); - PythonException.ThrowIfIsNull(obj); } diff --git a/src/runtime/pyiter.cs b/src/runtime/pyiter.cs index ee07bcecf..4ad761db7 100644 --- a/src/runtime/pyiter.cs +++ b/src/runtime/pyiter.cs @@ -26,18 +26,22 @@ public PyIter(IntPtr ptr) : base(ptr) } /// - /// PyIter Constructor + /// PyIter factory function. /// /// - /// Creates a Python iterator from an iterable. Like doing "iter(iterable)" in python. + /// Create a new PyIter from a given iterable. Like doing "iter(iterable)" in python. /// - public PyIter(PyObject iterable) + /// + /// + public static PyIter GetIter(PyObject iterable) { - obj = Runtime.PyObject_GetIter(iterable.obj); - if (obj == IntPtr.Zero) + if (iterable == null) { - throw new PythonException(); + throw new ArgumentNullException(); } + IntPtr val = Runtime.PyObject_GetIter(iterable.obj); + PythonException.ThrowIfIsNull(val); + return new PyIter(val); } protected override void Dispose(bool disposing) diff --git a/src/runtime/pylist.cs b/src/runtime/pylist.cs index 80267d81a..dcb0ea78f 100644 --- a/src/runtime/pylist.cs +++ b/src/runtime/pylist.cs @@ -28,6 +28,16 @@ public PyList(IntPtr ptr) : base(ptr) internal PyList(BorrowedReference reference) : base(reference) { } + private static IntPtr FromObject(PyObject o) + { + if (o == null || !IsListType(o)) + { + throw new ArgumentException("object is not a list"); + } + Runtime.XIncref(o.obj); + return o.obj; + } + /// /// PyList Constructor /// @@ -36,14 +46,8 @@ internal PyList(BorrowedReference reference) : base(reference) { } /// ArgumentException will be thrown if the given object is not a /// Python list object. /// - public PyList(PyObject o) + public PyList(PyObject o) : base(FromObject(o)) { - if (!IsListType(o)) - { - throw new ArgumentException("object is not a list"); - } - Runtime.XIncref(o.obj); - obj = o.obj; } @@ -53,36 +57,40 @@ public PyList(PyObject o) /// /// Creates a new empty Python list object. /// - public PyList() + public PyList() : base(Runtime.PyList_New(0)) { - obj = Runtime.PyList_New(0); if (obj == IntPtr.Zero) { throw new PythonException(); } } - - /// - /// PyList Constructor - /// - /// - /// Creates a new Python list object from an array of PyObjects. - /// - public PyList(PyObject[] items) + private static IntPtr FromArray(PyObject[] items) { int count = items.Length; - obj = Runtime.PyList_New(count); + IntPtr val = Runtime.PyList_New(count); for (var i = 0; i < count; i++) { IntPtr ptr = items[i].obj; Runtime.XIncref(ptr); - int r = Runtime.PyList_SetItem(obj, i, ptr); + int r = Runtime.PyList_SetItem(val, i, ptr); if (r < 0) { + Runtime.Py_DecRef(val); throw new PythonException(); } } + return val; + } + + /// + /// PyList Constructor + /// + /// + /// Creates a new Python list object from an array of PyObjects. + /// + public PyList(PyObject[] items) : base(FromArray(items)) + { } diff --git a/src/runtime/pylong.cs b/src/runtime/pylong.cs index fc101105f..87cc7d2a5 100644 --- a/src/runtime/pylong.cs +++ b/src/runtime/pylong.cs @@ -31,16 +31,26 @@ public PyLong(IntPtr ptr) : base(ptr) /// ArgumentException will be thrown if the given object is not a /// Python long object. /// - public PyLong(PyObject o) + public PyLong(PyObject o) : base(FromObject(o)) { - if (!IsLongType(o)) + } + + private static IntPtr FromObject(PyObject o) + { + if (o == null || !IsLongType(o)) { throw new ArgumentException("object is not a long"); } Runtime.XIncref(o.obj); - obj = o.obj; + return o.obj; } + private static IntPtr FromInt(int value) + { + IntPtr val = Runtime.PyLong_FromLong(value); + PythonException.ThrowIfIsNull(val); + return val; + } /// /// PyLong Constructor @@ -48,10 +58,8 @@ public PyLong(PyObject o) /// /// Creates a new PyLong from an int32 value. /// - public PyLong(int value) + public PyLong(int value) : base(FromInt(value)) { - obj = Runtime.PyLong_FromLong(value); - PythonException.ThrowIfIsNull(obj); } @@ -62,25 +70,34 @@ public PyLong(int value) /// Creates a new PyLong from a uint32 value. /// [CLSCompliant(false)] - public PyLong(uint value) + public PyLong(uint value) : base(FromInt((int)value)) { - obj = Runtime.PyLong_FromLong(value); - PythonException.ThrowIfIsNull(obj); } + private 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) + public PyLong(long value) : base(FromLong(value)) { - obj = Runtime.PyLong_FromLongLong(value); - PythonException.ThrowIfIsNull(obj); } + private static IntPtr FromULong(ulong value) + { + IntPtr val = Runtime.PyLong_FromUnsignedLongLong(value); + PythonException.ThrowIfIsNull(val); + return val; + } /// /// PyLong Constructor @@ -89,10 +106,8 @@ public PyLong(long value) /// Creates a new PyLong from a uint64 value. /// [CLSCompliant(false)] - public PyLong(ulong value) + public PyLong(ulong value) : base(FromULong(value)) { - obj = Runtime.PyLong_FromUnsignedLongLong(value); - PythonException.ThrowIfIsNull(obj); } @@ -102,10 +117,8 @@ public PyLong(ulong value) /// /// Creates a new PyLong from an int16 value. /// - public PyLong(short value) + public PyLong(short value) : base(FromInt((int)value)) { - obj = Runtime.PyLong_FromLong(value); - PythonException.ThrowIfIsNull(obj); } @@ -116,10 +129,8 @@ public PyLong(short value) /// Creates a new PyLong from an uint16 value. /// [CLSCompliant(false)] - public PyLong(ushort value) + public PyLong(ushort value) : base(FromInt((int)value)) { - obj = Runtime.PyLong_FromLong(value); - PythonException.ThrowIfIsNull(obj); } @@ -129,10 +140,8 @@ public PyLong(ushort value) /// /// Creates a new PyLong from a byte value. /// - public PyLong(byte value) + public PyLong(byte value) : base(FromInt((int)value)) { - obj = Runtime.PyLong_FromLong(value); - PythonException.ThrowIfIsNull(obj); } @@ -143,12 +152,16 @@ public PyLong(byte value) /// Creates a new PyLong from an sbyte value. /// [CLSCompliant(false)] - public PyLong(sbyte value) + public PyLong(sbyte value) : base(FromInt((int)value)) { - obj = Runtime.PyLong_FromLong(value); - PythonException.ThrowIfIsNull(obj); } + private static IntPtr FromDouble(double value) + { + IntPtr val = Runtime.PyLong_FromDouble(value); + PythonException.ThrowIfIsNull(val); + return val; + } /// /// PyLong Constructor @@ -156,12 +169,16 @@ public PyLong(sbyte value) /// /// Creates a new PyLong from an double value. /// - public PyLong(double value) + public PyLong(double value) : base(FromDouble(value)) { - obj = Runtime.PyLong_FromDouble(value); - PythonException.ThrowIfIsNull(obj); } + private static IntPtr FromString(string value) + { + IntPtr val = Runtime.PyLong_FromString(value, IntPtr.Zero, 0); + PythonException.ThrowIfIsNull(val); + return val; + } /// /// PyLong Constructor @@ -169,10 +186,8 @@ public PyLong(double value) /// /// Creates a new PyLong from a string value. /// - public PyLong(string value) + public PyLong(string value) : base(FromString(value)) { - obj = Runtime.PyLong_FromString(value, IntPtr.Zero, 0); - PythonException.ThrowIfIsNull(obj); } diff --git a/src/runtime/pynumber.cs b/src/runtime/pynumber.cs index 4f7373a8c..1af67b4e0 100644 --- a/src/runtime/pynumber.cs +++ b/src/runtime/pynumber.cs @@ -5,7 +5,6 @@ namespace Python.Runtime /// /// Represents a generic Python number. The methods of this class are /// equivalent to the Python "abstract number API". See - /// PY2: https://docs.python.org/2/c-api/number.html /// PY3: https://docs.python.org/3/c-api/number.html /// for details. /// @@ -18,11 +17,6 @@ protected PyNumber(IntPtr ptr) : base(ptr) { } - protected PyNumber() - { - } - - /// /// IsNumberType Method /// diff --git a/src/runtime/pyobject.cs b/src/runtime/pyobject.cs index f456fd69d..a7f5e8305 100644 --- a/src/runtime/pyobject.cs +++ b/src/runtime/pyobject.cs @@ -69,17 +69,6 @@ internal PyObject(BorrowedReference reference) #endif } - // Protected default constructor to allow subclasses to manage - // initialization in different ways as appropriate. - [Obsolete("Please, always use PyObject(*Reference)")] - protected PyObject() - { - Finalizer.Instance.ThrottledCollect(); -#if TRACE_ALLOC - Traceback = new StackTrace(1); -#endif - } - // Ensure that encapsulated Python object is decref'ed appropriately // when the managed wrapper is garbage-collected. ~PyObject() @@ -710,7 +699,7 @@ public PyObject GetIterator() /// public IEnumerator GetEnumerator() { - return new PyIter(this); + return PyIter.GetIter(this); } diff --git a/src/runtime/pysequence.cs b/src/runtime/pysequence.cs index 8df13f737..1850ef7de 100644 --- a/src/runtime/pysequence.cs +++ b/src/runtime/pysequence.cs @@ -18,10 +18,6 @@ protected PySequence(IntPtr ptr) : base(ptr) internal PySequence(BorrowedReference reference) : base(reference) { } - protected PySequence() - { - } - /// /// IsSequenceType Method diff --git a/src/runtime/pystring.cs b/src/runtime/pystring.cs index cb18024c5..b3d0dc86d 100644 --- a/src/runtime/pystring.cs +++ b/src/runtime/pystring.cs @@ -26,6 +26,16 @@ public PyString(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 /// @@ -34,27 +44,25 @@ public PyString(IntPtr ptr) : base(ptr) /// An ArgumentException will be thrown if the given object is not /// a Python string object. /// - public PyString(PyObject o) + public PyString(PyObject o) : base(FromObject(o)) { - if (!IsStringType(o)) - { - throw new ArgumentException("object is not a string"); - } - Runtime.XIncref(o.obj); - obj = o.obj; } + private static IntPtr FromString(string s) + { + IntPtr val = Runtime.PyUnicode_FromUnicode(s, s.Length); + PythonException.ThrowIfIsNull(val); + return val; + } /// /// PyString Constructor /// /// /// Creates a Python string from a managed string. /// - public PyString(string s) + public PyString(string s) : base(FromString(s)) { - obj = Runtime.PyUnicode_FromUnicode(s, s.Length); - PythonException.ThrowIfIsNull(obj); } diff --git a/src/runtime/pytuple.cs b/src/runtime/pytuple.cs index 259d7ae0f..530ced3d2 100644 --- a/src/runtime/pytuple.cs +++ b/src/runtime/pytuple.cs @@ -31,6 +31,15 @@ public PyTuple(IntPtr ptr) : base(ptr) /// internal PyTuple(BorrowedReference reference) : base(reference) { } + private static IntPtr FromObject(PyObject o) + { + if (o == null || !IsTupleType(o)) + { + throw new ArgumentException("object is not a tuple"); + } + Runtime.XIncref(o.obj); + return o.obj; + } /// /// PyTuple Constructor @@ -40,14 +49,8 @@ internal PyTuple(BorrowedReference reference) : base(reference) { } /// ArgumentException will be thrown if the given object is not a /// Python tuple object. /// - public PyTuple(PyObject o) + public PyTuple(PyObject o) : base(FromObject(o)) { - if (!IsTupleType(o)) - { - throw new ArgumentException("object is not a tuple"); - } - Runtime.XIncref(o.obj); - obj = o.obj; } @@ -57,12 +60,28 @@ public PyTuple(PyObject o) /// /// Creates a new empty PyTuple. /// - public PyTuple() + public PyTuple() : base(Runtime.PyTuple_New(0)) { - obj = Runtime.PyTuple_New(0); PythonException.ThrowIfIsNull(obj); } + private static IntPtr FromArray(PyObject[] items) + { + int count = items.Length; + IntPtr val = Runtime.PyTuple_New(count); + for (var i = 0; i < count; i++) + { + IntPtr ptr = items[i].obj; + Runtime.XIncref(ptr); + int res = Runtime.PyTuple_SetItem(val, i, ptr); + if (res != 0) + { + Runtime.Py_DecRef(val); + throw new PythonException(); + } + } + return val; + } /// /// PyTuple Constructor @@ -73,17 +92,8 @@ public PyTuple() /// See caveats about PyTuple_SetItem: /// https://www.coursehero.com/file/p4j2ogg/important-exceptions-to-this-rule-PyTupleSetItem-and-PyListSetItem-These/ /// - public PyTuple(PyObject[] items) + public PyTuple(PyObject[] items) : base(FromArray(items)) { - int count = items.Length; - obj = Runtime.PyTuple_New(count); - for (var i = 0; i < count; i++) - { - IntPtr ptr = items[i].obj; - Runtime.XIncref(ptr); - int res = Runtime.PyTuple_SetItem(obj, i, ptr); - PythonException.ThrowIfIsNotZero(res); - } }