| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -22,6 +22,7 @@ See [Mixins/collections.py](src/runtime/Mixins/collections.py). | |||
| 22 | 22 | - .NET arrays implement Python buffer protocol | |
| 23 | 23 | - Python.NET will correctly resolve .NET methods, that accept `PyList`, `PyInt`, | |
| 24 | 24 | and other `PyObject` derived types when called from Python. | |
| 25 | + - `PyIterable` type, that wraps any iterable object in Python | ||
| 25 | 26 | ||
| 26 | 27 | ||
| 27 | 28 | ### Changed | |
@@ -67,6 +68,8 @@ See [Mixins/collections.py](src/runtime/Mixins/collections.py). | |||
| 67 | 68 | - BREAKING: When trying to convert Python `int` to `System.Object`, result will | |
| 68 | 69 | be of type `PyInt` instead of `System.Int32` due to possible loss of information. | |
| 69 | 70 | Python `float` will continue to be converted to `System.Double`. | |
| 71 | + - BREAKING: `PyObject` no longer implements `IEnumerable<PyObject>`. | ||
| 72 | + Instead, `PyIterable` does that. | ||
| 70 | 73 | ||
| 71 | 74 | ### Fixed | |
| 72 | 75 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -45,12 +45,12 @@ static void TupleConversionsGeneric<T, TTuple>() | |||
| 45 | 45 | [Test] | |
| 46 | 46 | public void TupleConversionsObject() | |
| 47 | 47 | { | |
| 48 | - TupleConversionsObject<ValueTuple<int, string, object>, ValueTuple>(); | ||
| 48 | + TupleConversionsObject<ValueTuple<double, string, object>, ValueTuple>(); | ||
| 49 | 49 | } | |
| 50 | 50 | static void TupleConversionsObject<T, TTuple>() | |
| 51 | 51 | { | |
| 52 | 52 | TupleCodec<TTuple>.Register(); | |
| 53 | - var tuple = Activator.CreateInstance(typeof(T), 42, "42", new object()); | ||
| 53 | + var tuple = Activator.CreateInstance(typeof(T), 42.0, "42", new object()); | ||
| 54 | 54 | T restored = default; | |
| 55 | 55 | using (var scope = Py.CreateScope()) | |
| 56 | 56 | { | |
@@ -66,11 +66,11 @@ static void TupleConversionsObject<T, TTuple>() | |||
| 66 | 66 | [Test] | |
| 67 | 67 | public void TupleRoundtripObject() | |
| 68 | 68 | { | |
| 69 | - TupleRoundtripObject<ValueTuple<int, string, object>, ValueTuple>(); | ||
| 69 | + TupleRoundtripObject<ValueTuple<double, string, object>, ValueTuple>(); | ||
| 70 | 70 | } | |
| 71 | 71 | static void TupleRoundtripObject<T, TTuple>() | |
| 72 | 72 | { | |
| 73 | - var tuple = Activator.CreateInstance(typeof(T), 42, "42", new object()); | ||
| 73 | + var tuple = Activator.CreateInstance(typeof(T), 42.0, "42", new object()); | ||
| 74 | 74 | var pyTuple = TupleCodec<TTuple>.Instance.TryEncode(tuple); | |
| 75 | 75 | Assert.IsTrue(TupleCodec<TTuple>.Instance.TryDecode(pyTuple, out object restored)); | |
| 76 | 76 | Assert.AreEqual(expected: tuple, actual: restored); | |
@@ -231,7 +231,7 @@ public void IterableDecoderTest() | |||
| 231 | 231 | //ensure a PyList can be converted to a plain IEnumerable | |
| 232 | 232 | System.Collections.IEnumerable plainEnumerable1 = null; | |
| 233 | 233 | Assert.DoesNotThrow(() => { codec.TryDecode(pyList, out plainEnumerable1); }); | |
| 234 | - CollectionAssert.AreEqual(plainEnumerable1, new List<object> { 1, 2, 3 }); | ||
| 234 | + CollectionAssert.AreEqual(plainEnumerable1.Cast<PyInt>().Select(i => i.ToInt32()), new List<object> { 1, 2, 3 }); | ||
| 235 | 235 | ||
| 236 | 236 | //can convert to any generic ienumerable. If the type is not assignable from the python element | |
| 237 | 237 | //it will lead to an empty iterable when decoding. TODO - should it throw? | |
@@ -271,7 +271,7 @@ public void IterableDecoderTest() | |||
| 271 | 271 | var fooType = foo.GetPythonType(); | |
| 272 | 272 | System.Collections.IEnumerable plainEnumerable2 = null; | |
| 273 | 273 | Assert.DoesNotThrow(() => { codec.TryDecode(pyList, out plainEnumerable2); }); | |
| 274 | - CollectionAssert.AreEqual(plainEnumerable2, new List<object> { 1, 2, 3 }); | ||
| 274 | + CollectionAssert.AreEqual(plainEnumerable2.Cast<PyInt>().Select(i => i.ToInt32()), new List<object> { 1, 2, 3 }); | ||
| 275 | 275 | ||
| 276 | 276 | //can convert to any generic ienumerable. If the type is not assignable from the python element | |
| 277 | 277 | //it will be an exception during TryDecode | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,5 +1,6 @@ | |||
| 1 | 1 | #nullable enable | |
| 2 | 2 | using System; | |
| 3 | + using System.Collections.Generic; | ||
| 3 | 4 | using System.IO; | |
| 4 | 5 | using System.Runtime.InteropServices; | |
| 5 | 6 | ||
@@ -68,5 +69,7 @@ internal static string ReadStringResource(this System.Reflection.Assembly assemb | |||
| 68 | 69 | using var reader = new StreamReader(stream); | |
| 69 | 70 | return reader.ReadToEnd(); | |
| 70 | 71 | } | |
| 72 | + | ||
| 73 | + public static IEnumerator<T> GetEnumerator<T>(this IEnumerator<T> enumerator) => enumerator; | ||
| 71 | 74 | } | |
| 72 | 75 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -174,7 +174,7 @@ internal static Type CreateDerivedType(string name, | |||
| 174 | 174 | { | |
| 175 | 175 | Runtime.XIncref(py_dict); | |
| 176 | 176 | using (var dict = new PyDict(py_dict)) | |
| 177 | - using (PyObject keys = dict.Keys()) | ||
| 177 | + using (PyIterable keys = dict.Keys()) | ||
| 178 | 178 | { | |
| 179 | 179 | foreach (PyObject pyKey in keys) | |
| 180 | 180 | { | |
@@ -223,7 +223,7 @@ internal static Type CreateDerivedType(string name, | |||
| 223 | 223 | { | |
| 224 | 224 | Runtime.XIncref(py_dict); | |
| 225 | 225 | using (var dict = new PyDict(py_dict)) | |
| 226 | - using (PyObject keys = dict.Keys()) | ||
| 226 | + using (PyIterable keys = dict.Keys()) | ||
| 227 | 227 | { | |
| 228 | 228 | foreach (PyObject pyKey in keys) | |
| 229 | 229 | { | |
@@ -439,19 +439,14 @@ private static void AddPythonMethod(string methodName, PyObject func, TypeBuilde | |||
| 439 | 439 | } | |
| 440 | 440 | ||
| 441 | 441 | using (PyObject pyReturnType = func.GetAttr("_clr_return_type_")) | |
| 442 | - using (PyObject pyArgTypes = func.GetAttr("_clr_arg_types_")) | ||
| 442 | + using (var pyArgTypes = PyIter.GetIter(func.GetAttr("_clr_arg_types_"))) | ||
| 443 | 443 | { | |
| 444 | 444 | var returnType = pyReturnType.AsManagedObject(typeof(Type)) as Type; | |
| 445 | 445 | if (returnType == null) | |
| 446 | 446 | { | |
| 447 | 447 | returnType = typeof(void); | |
| 448 | 448 | } | |
| 449 | 449 | ||
| 450 | - if (!pyArgTypes.IsIterable()) | ||
| 451 | - { | ||
| 452 | - throw new ArgumentException("_clr_arg_types_ must be a list or tuple of CLR types"); | ||
| 453 | - } | ||
| 454 | - | ||
| 455 | 450 | var argTypes = new List<Type>(); | |
| 456 | 451 | foreach (PyObject pyArgType in pyArgTypes) | |
| 457 | 452 | { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -8,7 +8,7 @@ namespace Python.Runtime | |||
| 8 | 8 | /// PY3: https://docs.python.org/3/c-api/dict.html | |
| 9 | 9 | /// for details. | |
| 10 | 10 | /// </summary> | |
| 11 | - public class PyDict : PyObject | ||
| 11 | + public class PyDict : PyIterable | ||
| 12 | 12 | { | |
| 13 | 13 | /// <summary> | |
| 14 | 14 | /// PyDict Constructor | |
@@ -102,14 +102,14 @@ public bool HasKey(string key) | |||
| 102 | 102 | /// <remarks> | |
| 103 | 103 | /// Returns a sequence containing the keys of the dictionary. | |
| 104 | 104 | /// </remarks> | |
| 105 | - public PyObject Keys() | ||
| 105 | + public PyIterable Keys() | ||
| 106 | 106 | { | |
| 107 | 107 | using var items = Runtime.PyDict_Keys(Reference); | |
| 108 | 108 | if (items.IsNull()) | |
| 109 | 109 | { | |
| 110 | 110 | throw PythonException.ThrowLastAsClrException(); | |
| 111 | 111 | } | |
| 112 | - return items.MoveToPyObject(); | ||
| 112 | + return new PyIterable(items.Steal()); | ||
| 113 | 113 | } | |
| 114 | 114 | ||
| 115 | 115 | ||
@@ -119,14 +119,14 @@ public PyObject Keys() | |||
| 119 | 119 | /// <remarks> | |
| 120 | 120 | /// Returns a sequence containing the values of the dictionary. | |
| 121 | 121 | /// </remarks> | |
| 122 | - public PyObject Values() | ||
| 122 | + public PyIterable Values() | ||
| 123 | 123 | { | |
| 124 | 124 | IntPtr items = Runtime.PyDict_Values(obj); | |
| 125 | 125 | if (items == IntPtr.Zero) | |
| 126 | 126 | { | |
| 127 | 127 | throw PythonException.ThrowLastAsClrException(); | |
| 128 | 128 | } | |
| 129 | - return new PyObject(items); | ||
| 129 | + return new PyIterable(items); | ||
| 130 | 130 | } | |
| 131 | 131 | ||
| 132 | 132 | ||
@@ -136,22 +136,14 @@ public PyObject Values() | |||
| 136 | 136 | /// <remarks> | |
| 137 | 137 | /// Returns a sequence containing the items of the dictionary. | |
| 138 | 138 | /// </remarks> | |
| 139 | - public PyObject Items() | ||
| 139 | + public PyIterable Items() | ||
| 140 | 140 | { | |
| 141 | - var items = Runtime.PyDict_Items(this.Reference); | ||
| 142 | - try | ||
| 143 | - { | ||
| 144 | - if (items.IsNull()) | ||
| 145 | - { | ||
| 146 | - throw PythonException.ThrowLastAsClrException(); | ||
| 147 | - } | ||
| 148 | - | ||
| 149 | - return items.MoveToPyObject(); | ||
| 150 | - } | ||
| 151 | - finally | ||
| 141 | + using var items = Runtime.PyDict_Items(this.Reference); | ||
| 142 | + if (items.IsNull()) | ||
| 152 | 143 | { | |
| 153 | - items.Dispose(); | ||
| 144 | + throw PythonException.ThrowLastAsClrException(); | ||
| 154 | 145 | } | |
| 146 | + return new PyIterable(items.Steal()); | ||
| 155 | 147 | } | |
| 156 | 148 | ||
| 157 | 149 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,28 @@ | |||
| 1 | + using System; | ||
| 2 | + using System.Collections; | ||
| 3 | + using System.Collections.Generic; | ||
| 4 | + | ||
| 5 | + namespace Python.Runtime | ||
| 6 | + { | ||
| 7 | + public class PyIterable : PyObject, IEnumerable<PyObject> | ||
| 8 | + { | ||
| 9 | + internal PyIterable(IntPtr ptr) : base(ptr) | ||
| 10 | + { | ||
| 11 | + } | ||
| 12 | + | ||
| 13 | + internal PyIterable(BorrowedReference reference) : base(reference) { } | ||
| 14 | + internal PyIterable(in StolenReference reference) : base(reference) { } | ||
| 15 | + | ||
| 16 | + /// <summary> | ||
| 17 | + /// Return a new PyIter object for the object. This allows any iterable | ||
| 18 | + /// python object to be iterated over in C#. A PythonException will be | ||
| 19 | + /// raised if the object is not iterable. | ||
| 20 | + /// </summary> | ||
| 21 | + public PyIter GetEnumerator() | ||
| 22 | + { | ||
| 23 | + return PyIter.GetIter(this); | ||
| 24 | + } | ||
| 25 | + IEnumerator<PyObject> IEnumerable<PyObject>.GetEnumerator() => this.GetEnumerator(); | ||
| 26 | + IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); | ||
| 27 | + } | ||
| 28 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -17,7 +17,7 @@ namespace Python.Runtime | |||
| 17 | 17 | /// </summary> | |
| 18 | 18 | [Serializable] | |
| 19 | 19 | [DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")] | |
| 20 | - public partial class PyObject : DynamicObject, IEnumerable<PyObject>, IDisposable | ||
| 20 | + public partial class PyObject : DynamicObject, IDisposable | ||
| 21 | 21 | { | |
| 22 | 22 | #if TRACE_ALLOC | |
| 23 | 23 | /// <summary> | |
@@ -80,7 +80,7 @@ internal PyObject(BorrowedReference reference) | |||
| 80 | 80 | #endif | |
| 81 | 81 | } | |
| 82 | 82 | ||
| 83 | - internal PyObject(StolenReference reference) | ||
| 83 | + internal PyObject(in StolenReference reference) | ||
| 84 | 84 | { | |
| 85 | 85 | if (reference == null) throw new ArgumentNullException(nameof(reference)); | |
| 86 | 86 | ||
@@ -703,21 +703,6 @@ public PyObject GetIterator() | |||
| 703 | 703 | return new PyObject(r); | |
| 704 | 704 | } | |
| 705 | 705 | ||
| 706 | - /// <summary> | ||
| 707 | - /// GetEnumerator Method | ||
| 708 | - /// </summary> | ||
| 709 | - /// <remarks> | ||
| 710 | - /// Return a new PyIter object for the object. This allows any iterable | ||
| 711 | - /// python object to be iterated over in C#. A PythonException will be | ||
| 712 | - /// raised if the object is not iterable. | ||
| 713 | - /// </remarks> | ||
| 714 | - public IEnumerator<PyObject> GetEnumerator() | ||
| 715 | - { | ||
| 716 | - return PyIter.GetIter(this); | ||
| 717 | - } | ||
| 718 | - IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); | ||
| 719 | - | ||
| 720 | - | ||
| 721 | 706 | /// <summary> | |
| 722 | 707 | /// Invoke Method | |
| 723 | 708 | /// </summary> | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,5 +1,4 @@ | |||
| 1 | 1 | using System; | |
| 2 | - using System.Collections; | ||
| 3 | 2 | ||
| 4 | 3 | namespace Python.Runtime | |
| 5 | 4 | { | |
@@ -10,13 +9,14 @@ namespace Python.Runtime | |||
| 10 | 9 | /// PY3: https://docs.python.org/3/c-api/sequence.html | |
| 11 | 10 | /// for details. | |
| 12 | 11 | /// </summary> | |
| 13 | - public class PySequence : PyObject, IEnumerable | ||
| 12 | + public class PySequence : PyIterable | ||
| 14 | 13 | { | |
| 15 | - protected PySequence(IntPtr ptr) : base(ptr) | ||
| 14 | + protected internal PySequence(IntPtr ptr) : base(ptr) | ||
| 16 | 15 | { | |
| 17 | 16 | } | |
| 18 | 17 | ||
| 19 | 18 | internal PySequence(BorrowedReference reference) : base(reference) { } | |
| 19 | + internal PySequence(StolenReference reference) : base(reference) { } | ||
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | 22 | /// <summary> | |
@@ -30,7 +30,6 @@ public static bool IsSequenceType(PyObject value) | |||
| 30 | 30 | return Runtime.PySequence_Check(value.obj); | |
| 31 | 31 | } | |
| 32 | 32 | ||
| 33 | - | ||
| 34 | 33 | /// <summary> | |
| 35 | 34 | /// GetSlice Method | |
| 36 | 35 | /// </summary> | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -387,7 +387,7 @@ public string Format() | |||
| 387 | 387 | using var traceback = PyModule.Import("traceback"); | |
| 388 | 388 | var buffer = new StringBuilder(); | |
| 389 | 389 | using var values = traceback.InvokeMethod("format_exception", copy.Type, copy.Value, copy.Traceback); | |
| 390 | - foreach (PyObject val in values) | ||
| 390 | + foreach (PyObject val in PyIter.GetIter(values)) | ||
| 391 | 391 | { | |
| 392 | 392 | buffer.Append(val); | |
| 393 | 393 | val.Dispose(); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments