From 1ef1e7ba5be974c4cc500c5d134641ceb96f6b9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joa=CC=83o=20Neves?= Date: Wed, 17 Jul 2024 19:06:31 +0100 Subject: [PATCH 01/12] Encoders no support specifying the target encoding type --- src/runtime/Codecs/EncoderGroup.cs | 4 ++-- src/runtime/Codecs/EnumPyIntCodec.cs | 7 +++---- src/runtime/Codecs/IPyObjectEncoder.cs | 3 ++- src/runtime/Codecs/PyObjectConversions.cs | 2 +- src/runtime/Codecs/RawProxyEncoder.cs | 2 +- src/runtime/Codecs/TupleCodecs.cs | 13 ++++++------- src/runtime/Converter.cs | 6 ++++++ 7 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/runtime/Codecs/EncoderGroup.cs b/src/runtime/Codecs/EncoderGroup.cs index 63abf35a3..97f14a512 100644 --- a/src/runtime/Codecs/EncoderGroup.cs +++ b/src/runtime/Codecs/EncoderGroup.cs @@ -28,13 +28,13 @@ public void Add(IPyObjectEncoder item) /// public bool CanEncode(Type type) => this.encoders.Any(encoder => encoder.CanEncode(type)); /// - public PyObject? TryEncode(object value) + public PyObject? TryEncode(object value, Type type) { if (value is null) throw new ArgumentNullException(nameof(value)); foreach (var encoder in this.GetEncoders(value.GetType())) { - var result = encoder.TryEncode(value); + var result = encoder.TryEncode(value, type); if (result != null) { return result; diff --git a/src/runtime/Codecs/EnumPyIntCodec.cs b/src/runtime/Codecs/EnumPyIntCodec.cs index 42f5eb1b2..5023d4395 100644 --- a/src/runtime/Codecs/EnumPyIntCodec.cs +++ b/src/runtime/Codecs/EnumPyIntCodec.cs @@ -46,12 +46,11 @@ public bool TryDecode(PyObject pyObj, out T? value) return false; } - public PyObject? TryEncode(object value) + public PyObject? TryEncode(object value, Type type) { if (value is null) return null; - - var enumType = value.GetType(); - if (!enumType.IsEnum) return null; + + if (!type.IsEnum) return null; try { diff --git a/src/runtime/Codecs/IPyObjectEncoder.cs b/src/runtime/Codecs/IPyObjectEncoder.cs index 94d19da90..1eab1f48b 100644 --- a/src/runtime/Codecs/IPyObjectEncoder.cs +++ b/src/runtime/Codecs/IPyObjectEncoder.cs @@ -13,6 +13,7 @@ public interface IPyObjectEncoder bool CanEncode(Type type); /// /// Attempts to encode CLR object into Python object + /// using the specified /// - PyObject? TryEncode(object value); + PyObject? TryEncode(object value, Type type); } diff --git a/src/runtime/Codecs/PyObjectConversions.cs b/src/runtime/Codecs/PyObjectConversions.cs index cde97c8c9..705253c20 100644 --- a/src/runtime/Codecs/PyObjectConversions.cs +++ b/src/runtime/Codecs/PyObjectConversions.cs @@ -54,7 +54,7 @@ public static void RegisterDecoder(IPyObjectDecoder decoder) foreach (var encoder in clrToPython.GetOrAdd(type, GetEncoders)) { - var result = encoder.TryEncode(obj); + var result = encoder.TryEncode(obj, type); if (result != null) return result; } diff --git a/src/runtime/Codecs/RawProxyEncoder.cs b/src/runtime/Codecs/RawProxyEncoder.cs index 37ad0487b..c02cb0a36 100644 --- a/src/runtime/Codecs/RawProxyEncoder.cs +++ b/src/runtime/Codecs/RawProxyEncoder.cs @@ -8,7 +8,7 @@ namespace Python.Runtime.Codecs /// public class RawProxyEncoder: IPyObjectEncoder { - public PyObject TryEncode(object value) + public PyObject TryEncode(object value, Type type) { if (value is null) throw new ArgumentNullException(nameof(value)); diff --git a/src/runtime/Codecs/TupleCodecs.cs b/src/runtime/Codecs/TupleCodecs.cs index ec8975e3a..631f2c49e 100644 --- a/src/runtime/Codecs/TupleCodecs.cs +++ b/src/runtime/Codecs/TupleCodecs.cs @@ -18,20 +18,19 @@ public bool CanEncode(Type type) && type.Name.StartsWith(typeof(TTuple).Name + '`'); } - public PyObject? TryEncode(object value) + public PyObject? TryEncode(object value, Type type) { if (value == null) return null; - var tupleType = value.GetType(); - if (tupleType == typeof(object)) return null; - if (!this.CanEncode(tupleType)) return null; - if (tupleType == typeof(TTuple)) return new PyTuple(); + if (type == typeof(object)) return null; + if (!this.CanEncode(type)) return null; + if (type == typeof(TTuple)) return new PyTuple(); - nint fieldCount = tupleType.GetGenericArguments().Length; + nint fieldCount = type.GetGenericArguments().Length; using var tuple = Runtime.PyTuple_New(fieldCount); PythonException.ThrowIfIsNull(tuple); int fieldIndex = 0; - foreach (FieldInfo field in tupleType.GetFields()) + foreach (FieldInfo field in type.GetFields()) { var item = field.GetValue(value); using var pyItem = Converter.ToPython(item, field.FieldType); diff --git a/src/runtime/Converter.cs b/src/runtime/Converter.cs index 50b33e60e..a6d12b069 100644 --- a/src/runtime/Converter.cs +++ b/src/runtime/Converter.cs @@ -987,5 +987,11 @@ public static PyObject ToPythonAs(this T? o) if (o is null) return Runtime.None; return Converter.ToPython(o, typeof(T)).MoveToPyObject(); } + + public static PyObject ToPythonAs(this object o, Type type) + { + if (o is null) return Runtime.None; + return Converter.ToPython(o, type).MoveToPyObject(); + } } } From 255201afbc81f382b74ebcb74ec9506ee67a83ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joa=CC=83o=20Neves?= Date: Thu, 18 Jul 2024 10:03:42 +0100 Subject: [PATCH 02/12] Fix build --- src/embed_tests/CodecGroups.cs | 4 ++-- src/embed_tests/Codecs.cs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/embed_tests/CodecGroups.cs b/src/embed_tests/CodecGroups.cs index 689e5b24c..f834c1ee2 100644 --- a/src/embed_tests/CodecGroups.cs +++ b/src/embed_tests/CodecGroups.cs @@ -48,12 +48,12 @@ public void Encodes() encoder2, }; - var uri = group.TryEncode(new Uri("data:")); + var uri = group.TryEncode(new Uri("data:"), typeof(Uri)); var clrObject = (CLRObject)ManagedType.GetManagedObject(uri); Assert.AreSame(encoder1, clrObject.inst); Assert.AreNotSame(encoder2, clrObject.inst); - var tuple = group.TryEncode(Tuple.Create(1)); + var tuple = group.TryEncode(Tuple.Create(1), typeof(Tuple)); clrObject = (CLRObject)ManagedType.GetManagedObject(tuple); Assert.AreSame(encoder0, clrObject.inst); } diff --git a/src/embed_tests/Codecs.cs b/src/embed_tests/Codecs.cs index c8b8ecb6e..c7fdf8283 100644 --- a/src/embed_tests/Codecs.cs +++ b/src/embed_tests/Codecs.cs @@ -71,7 +71,7 @@ public void TupleRoundtripObject() static void TupleRoundtripObject() { var tuple = Activator.CreateInstance(typeof(T), 42.0, "42", new object()); - using var pyTuple = TupleCodec.Instance.TryEncode(tuple); + using var pyTuple = TupleCodec.Instance.TryEncode(tuple, typeof(T)); Assert.IsTrue(TupleCodec.Instance.TryDecode(pyTuple, out object restored)); Assert.AreEqual(expected: tuple, actual: restored); } @@ -85,7 +85,7 @@ public void TupleRoundtripGeneric() static void TupleRoundtripGeneric() { var tuple = Activator.CreateInstance(typeof(T), 42, "42", new object()); - using var pyTuple = TupleCodec.Instance.TryEncode(tuple); + using var pyTuple = TupleCodec.Instance.TryEncode(tuple, typeof(T)); Assert.IsTrue(TupleCodec.Instance.TryDecode(pyTuple, out T restored)); Assert.AreEqual(expected: tuple, actual: restored); } @@ -438,7 +438,7 @@ public bool TryDecode(PyObject pyObj, out T value) return true; } - public PyObject TryEncode(object value) + public PyObject TryEncode(object value, Type type) { var error = (ValueErrorWrapper)value; return PythonEngine.Eval("ValueError").Invoke(error.Message.ToPython()); @@ -478,7 +478,7 @@ public bool TryDecode(PyObject pyObj, out T value) class ObjectToEncoderInstanceEncoder : IPyObjectEncoder { public bool CanEncode(Type type) => type == typeof(T); - public PyObject TryEncode(object value) => PyObject.FromManagedObject(this); + public PyObject TryEncode(object value, Type type) => PyObject.FromManagedObject(this); } /// From 37c4d049a3cf81cfa5c14a0bcf19b363a14e3519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joa=CC=83o=20Neves?= Date: Thu, 18 Jul 2024 17:47:20 +0100 Subject: [PATCH 03/12] Add unit test --- src/embed_tests/CodecGroups.cs | 4 +-- src/embed_tests/Codecs.cs | 40 ++++++++++++++++++--- src/embed_tests/Python.EmbeddingTest.csproj | 1 + src/runtime/Codecs/EncoderGroup.cs | 4 +-- src/runtime/Codecs/EnumPyIntCodec.cs | 6 ++-- src/runtime/Codecs/IPyObjectEncoder.cs | 3 +- src/runtime/Codecs/PyObjectConversions.cs | 2 +- src/runtime/Codecs/RawProxyEncoder.cs | 4 +-- src/runtime/Codecs/TupleCodecs.cs | 3 +- src/runtime/PythonTypes/PyObject.cs | 8 ++--- 10 files changed, 54 insertions(+), 21 deletions(-) diff --git a/src/embed_tests/CodecGroups.cs b/src/embed_tests/CodecGroups.cs index f834c1ee2..689e5b24c 100644 --- a/src/embed_tests/CodecGroups.cs +++ b/src/embed_tests/CodecGroups.cs @@ -48,12 +48,12 @@ public void Encodes() encoder2, }; - var uri = group.TryEncode(new Uri("data:"), typeof(Uri)); + var uri = group.TryEncode(new Uri("data:")); var clrObject = (CLRObject)ManagedType.GetManagedObject(uri); Assert.AreSame(encoder1, clrObject.inst); Assert.AreNotSame(encoder2, clrObject.inst); - var tuple = group.TryEncode(Tuple.Create(1), typeof(Tuple)); + var tuple = group.TryEncode(Tuple.Create(1)); clrObject = (CLRObject)ManagedType.GetManagedObject(tuple); Assert.AreSame(encoder0, clrObject.inst); } diff --git a/src/embed_tests/Codecs.cs b/src/embed_tests/Codecs.cs index c7fdf8283..1a815e2cd 100644 --- a/src/embed_tests/Codecs.cs +++ b/src/embed_tests/Codecs.cs @@ -71,7 +71,7 @@ public void TupleRoundtripObject() static void TupleRoundtripObject() { var tuple = Activator.CreateInstance(typeof(T), 42.0, "42", new object()); - using var pyTuple = TupleCodec.Instance.TryEncode(tuple, typeof(T)); + using var pyTuple = TupleCodec.Instance.TryEncode(tuple); Assert.IsTrue(TupleCodec.Instance.TryDecode(pyTuple, out object restored)); Assert.AreEqual(expected: tuple, actual: restored); } @@ -85,7 +85,7 @@ public void TupleRoundtripGeneric() static void TupleRoundtripGeneric() { var tuple = Activator.CreateInstance(typeof(T), 42, "42", new object()); - using var pyTuple = TupleCodec.Instance.TryEncode(tuple, typeof(T)); + using var pyTuple = TupleCodec.Instance.TryEncode(tuple); Assert.IsTrue(TupleCodec.Instance.TryDecode(pyTuple, out T restored)); Assert.AreEqual(expected: tuple, actual: restored); } @@ -339,6 +339,26 @@ public void ExceptionDecoded() Assert.AreEqual(TestExceptionMessage, error.Message); } + [Test] + public void ExplicitObjectInterfaceEncoded() + { + var obj = new ExplicitInterfaceObject(); + + // explicitly pass an interface (but not a generic type argument) to simulate a scenario where the type is not know at build time + // var encoder = new InterfaceEncoder(typeof(IObjectInterface)); + // PyObjectConversions.RegisterEncoder(encoder); + + using var scope = Py.CreateScope(); + scope.Exec(@" +def call(obj): + return dir(obj) +"); + var callFunc = scope.Get("call"); + var members = callFunc.Invoke(obj.ToPythonAs(typeof(IObjectInterface))).As(); + CollectionAssert.Contains(members, nameof(IObjectInterface.MemberFromInterface)); + CollectionAssert.DoesNotContain(members, nameof(ExplicitInterfaceObject.MemberFromObject)); + } + [Test] public void DateTimeDecoded() { @@ -438,7 +458,7 @@ public bool TryDecode(PyObject pyObj, out T value) return true; } - public PyObject TryEncode(object value, Type type) + public PyObject TryEncode(object value) { var error = (ValueErrorWrapper)value; return PythonEngine.Eval("ValueError").Invoke(error.Message.ToPython()); @@ -478,7 +498,7 @@ public bool TryDecode(PyObject pyObj, out T value) class ObjectToEncoderInstanceEncoder : IPyObjectEncoder { public bool CanEncode(Type type) => type == typeof(T); - public PyObject TryEncode(object value, Type type) => PyObject.FromManagedObject(this); + public PyObject TryEncode(object value) => PyObject.FromManagedObject(this); } /// @@ -533,4 +553,16 @@ public bool TryDecode(PyObject pyObj, out T value) return true; } } + + interface IObjectInterface + { + int MemberFromInterface { get; } + } + + class ExplicitInterfaceObject : IObjectInterface + { + int IObjectInterface.MemberFromInterface { get; } + + public int MemberFromObject { get; } + } } diff --git a/src/embed_tests/Python.EmbeddingTest.csproj b/src/embed_tests/Python.EmbeddingTest.csproj index 4993994d3..be36ca787 100644 --- a/src/embed_tests/Python.EmbeddingTest.csproj +++ b/src/embed_tests/Python.EmbeddingTest.csproj @@ -2,6 +2,7 @@ net472;net6.0 + LatestMajor ..\pythonnet.snk true diff --git a/src/runtime/Codecs/EncoderGroup.cs b/src/runtime/Codecs/EncoderGroup.cs index 97f14a512..63abf35a3 100644 --- a/src/runtime/Codecs/EncoderGroup.cs +++ b/src/runtime/Codecs/EncoderGroup.cs @@ -28,13 +28,13 @@ public void Add(IPyObjectEncoder item) /// public bool CanEncode(Type type) => this.encoders.Any(encoder => encoder.CanEncode(type)); /// - public PyObject? TryEncode(object value, Type type) + public PyObject? TryEncode(object value) { if (value is null) throw new ArgumentNullException(nameof(value)); foreach (var encoder in this.GetEncoders(value.GetType())) { - var result = encoder.TryEncode(value, type); + var result = encoder.TryEncode(value); if (result != null) { return result; diff --git a/src/runtime/Codecs/EnumPyIntCodec.cs b/src/runtime/Codecs/EnumPyIntCodec.cs index 5023d4395..8c6bc234e 100644 --- a/src/runtime/Codecs/EnumPyIntCodec.cs +++ b/src/runtime/Codecs/EnumPyIntCodec.cs @@ -46,11 +46,11 @@ public bool TryDecode(PyObject pyObj, out T? value) return false; } - public PyObject? TryEncode(object value, Type type) + public PyObject? TryEncode(object value) { if (value is null) return null; - - if (!type.IsEnum) return null; + + if (!value.GetType().IsEnum) return null; try { diff --git a/src/runtime/Codecs/IPyObjectEncoder.cs b/src/runtime/Codecs/IPyObjectEncoder.cs index 1eab1f48b..94d19da90 100644 --- a/src/runtime/Codecs/IPyObjectEncoder.cs +++ b/src/runtime/Codecs/IPyObjectEncoder.cs @@ -13,7 +13,6 @@ public interface IPyObjectEncoder bool CanEncode(Type type); /// /// Attempts to encode CLR object into Python object - /// using the specified /// - PyObject? TryEncode(object value, Type type); + PyObject? TryEncode(object value); } diff --git a/src/runtime/Codecs/PyObjectConversions.cs b/src/runtime/Codecs/PyObjectConversions.cs index 705253c20..cde97c8c9 100644 --- a/src/runtime/Codecs/PyObjectConversions.cs +++ b/src/runtime/Codecs/PyObjectConversions.cs @@ -54,7 +54,7 @@ public static void RegisterDecoder(IPyObjectDecoder decoder) foreach (var encoder in clrToPython.GetOrAdd(type, GetEncoders)) { - var result = encoder.TryEncode(obj, type); + var result = encoder.TryEncode(obj); if (result != null) return result; } diff --git a/src/runtime/Codecs/RawProxyEncoder.cs b/src/runtime/Codecs/RawProxyEncoder.cs index c02cb0a36..46d9205cb 100644 --- a/src/runtime/Codecs/RawProxyEncoder.cs +++ b/src/runtime/Codecs/RawProxyEncoder.cs @@ -8,11 +8,11 @@ namespace Python.Runtime.Codecs /// public class RawProxyEncoder: IPyObjectEncoder { - public PyObject TryEncode(object value, Type type) + public PyObject TryEncode(object value) { if (value is null) throw new ArgumentNullException(nameof(value)); - return PyObject.FromManagedObject(value); + return PyObject.FromManagedObject(value, value.GetType()); } public virtual bool CanEncode(Type type) => false; diff --git a/src/runtime/Codecs/TupleCodecs.cs b/src/runtime/Codecs/TupleCodecs.cs index 631f2c49e..432b3eb7d 100644 --- a/src/runtime/Codecs/TupleCodecs.cs +++ b/src/runtime/Codecs/TupleCodecs.cs @@ -18,10 +18,11 @@ public bool CanEncode(Type type) && type.Name.StartsWith(typeof(TTuple).Name + '`'); } - public PyObject? TryEncode(object value, Type type) + public PyObject? TryEncode(object value) { if (value == null) return null; + var type = value.GetType(); if (type == typeof(object)) return null; if (!this.CanEncode(type)) return null; if (type == typeof(TTuple)) return new PyTuple(); diff --git a/src/runtime/PythonTypes/PyObject.cs b/src/runtime/PythonTypes/PyObject.cs index cf0c2a03f..554c30697 100644 --- a/src/runtime/PythonTypes/PyObject.cs +++ b/src/runtime/PythonTypes/PyObject.cs @@ -25,7 +25,7 @@ public partial class PyObject : DynamicObject, IDisposable, ISerializable /// Trace stack for PyObject's construction /// public StackTrace Traceback { get; } = new StackTrace(1); -#endif +#endif protected IntPtr rawPtr = IntPtr.Zero; internal readonly int run = Runtime.GetRun(); @@ -136,14 +136,14 @@ public IntPtr Handle /// Given an arbitrary managed object, return a Python instance that /// reflects the managed object. /// - public static PyObject FromManagedObject(object ob) + public static PyObject FromManagedObject(object ob, Type? type = null) { // Special case: if ob is null, we return None. if (ob == null) { return new PyObject(Runtime.PyNone); } - return CLRObject.GetReference(ob).MoveToPyObject(); + return CLRObject.GetReference(ob, type ?? ob.GetType()).MoveToPyObject(); } /// @@ -235,7 +235,7 @@ public void Dispose() { GC.SuppressFinalize(this); Dispose(true); - + } internal StolenReference Steal() From 4fbf04c34783e717ef096ffb7fe7268611ee324f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joa=CC=83o=20Neves?= Date: Thu, 18 Jul 2024 17:53:30 +0100 Subject: [PATCH 04/12] Revert unnecessary changes --- src/runtime/Codecs/EnumPyIntCodec.cs | 3 ++- src/runtime/Codecs/RawProxyEncoder.cs | 2 +- src/runtime/Codecs/TupleCodecs.cs | 12 ++++++------ src/runtime/PythonTypes/PyObject.cs | 1 - 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/runtime/Codecs/EnumPyIntCodec.cs b/src/runtime/Codecs/EnumPyIntCodec.cs index 8c6bc234e..42f5eb1b2 100644 --- a/src/runtime/Codecs/EnumPyIntCodec.cs +++ b/src/runtime/Codecs/EnumPyIntCodec.cs @@ -50,7 +50,8 @@ public bool TryDecode(PyObject pyObj, out T? value) { if (value is null) return null; - if (!value.GetType().IsEnum) return null; + var enumType = value.GetType(); + if (!enumType.IsEnum) return null; try { diff --git a/src/runtime/Codecs/RawProxyEncoder.cs b/src/runtime/Codecs/RawProxyEncoder.cs index 46d9205cb..37ad0487b 100644 --- a/src/runtime/Codecs/RawProxyEncoder.cs +++ b/src/runtime/Codecs/RawProxyEncoder.cs @@ -12,7 +12,7 @@ public PyObject TryEncode(object value) { if (value is null) throw new ArgumentNullException(nameof(value)); - return PyObject.FromManagedObject(value, value.GetType()); + return PyObject.FromManagedObject(value); } public virtual bool CanEncode(Type type) => false; diff --git a/src/runtime/Codecs/TupleCodecs.cs b/src/runtime/Codecs/TupleCodecs.cs index 432b3eb7d..ec8975e3a 100644 --- a/src/runtime/Codecs/TupleCodecs.cs +++ b/src/runtime/Codecs/TupleCodecs.cs @@ -22,16 +22,16 @@ public bool CanEncode(Type type) { if (value == null) return null; - var type = value.GetType(); - if (type == typeof(object)) return null; - if (!this.CanEncode(type)) return null; - if (type == typeof(TTuple)) return new PyTuple(); + var tupleType = value.GetType(); + if (tupleType == typeof(object)) return null; + if (!this.CanEncode(tupleType)) return null; + if (tupleType == typeof(TTuple)) return new PyTuple(); - nint fieldCount = type.GetGenericArguments().Length; + nint fieldCount = tupleType.GetGenericArguments().Length; using var tuple = Runtime.PyTuple_New(fieldCount); PythonException.ThrowIfIsNull(tuple); int fieldIndex = 0; - foreach (FieldInfo field in type.GetFields()) + foreach (FieldInfo field in tupleType.GetFields()) { var item = field.GetValue(value); using var pyItem = Converter.ToPython(item, field.FieldType); diff --git a/src/runtime/PythonTypes/PyObject.cs b/src/runtime/PythonTypes/PyObject.cs index 554c30697..a62f92ee7 100644 --- a/src/runtime/PythonTypes/PyObject.cs +++ b/src/runtime/PythonTypes/PyObject.cs @@ -235,7 +235,6 @@ public void Dispose() { GC.SuppressFinalize(this); Dispose(true); - } internal StolenReference Steal() From cf8ff1f1d9e8514660b3bcc8ca79543fa49ee971 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joa=CC=83o=20Neves?= Date: Thu, 18 Jul 2024 17:56:30 +0100 Subject: [PATCH 05/12] Add test description --- src/embed_tests/Codecs.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/embed_tests/Codecs.cs b/src/embed_tests/Codecs.cs index 1a815e2cd..90eb26669 100644 --- a/src/embed_tests/Codecs.cs +++ b/src/embed_tests/Codecs.cs @@ -339,22 +339,19 @@ public void ExceptionDecoded() Assert.AreEqual(TestExceptionMessage, error.Message); } - [Test] + [Test(Description = "Tests encoding of an object that explicitly implements an interface.")] public void ExplicitObjectInterfaceEncoded() { var obj = new ExplicitInterfaceObject(); - - // explicitly pass an interface (but not a generic type argument) to simulate a scenario where the type is not know at build time - // var encoder = new InterfaceEncoder(typeof(IObjectInterface)); - // PyObjectConversions.RegisterEncoder(encoder); - using var scope = Py.CreateScope(); scope.Exec(@" def call(obj): return dir(obj) "); var callFunc = scope.Get("call"); - var members = callFunc.Invoke(obj.ToPythonAs(typeof(IObjectInterface))).As(); + // explicitly pass an interface (but not a generic type argument) to simulate a scenario where the type is not know at build time + var callArg = obj.ToPythonAs(typeof(IObjectInterface)); + var members = callFunc.Invoke(callArg).As(); CollectionAssert.Contains(members, nameof(IObjectInterface.MemberFromInterface)); CollectionAssert.DoesNotContain(members, nameof(ExplicitInterfaceObject.MemberFromObject)); } From bc111365482557e85f7474e68d2d76dc5ff8fff3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joa=CC=83o=20Neves?= Date: Thu, 18 Jul 2024 18:01:07 +0100 Subject: [PATCH 06/12] Remove warning --- src/runtime/Converter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/Converter.cs b/src/runtime/Converter.cs index a6d12b069..a1b5703a5 100644 --- a/src/runtime/Converter.cs +++ b/src/runtime/Converter.cs @@ -988,7 +988,7 @@ public static PyObject ToPythonAs(this T? o) return Converter.ToPython(o, typeof(T)).MoveToPyObject(); } - public static PyObject ToPythonAs(this object o, Type type) + public static PyObject ToPythonAs(this object? o, Type type) { if (o is null) return Runtime.None; return Converter.ToPython(o, type).MoveToPyObject(); From 1073b03ef600925040721ea5bca0160eff6ecdb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joa=CC=83o=20Neves?= Date: Thu, 18 Jul 2024 18:10:42 +0100 Subject: [PATCH 07/12] Update authors and changelog @microsoft-github-policy-service agree --- AUTHORS.md | 1 + CHANGELOG.md | 87 ++++++++++++++++++++++++---------------------------- 2 files changed, 41 insertions(+), 47 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index 18435671c..f0d9f96ec 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -44,6 +44,7 @@ - Jan Krivanek ([@jakrivan](https://github.com/jakrivan)) - Jeff Reback ([@jreback](https://github.com/jreback)) - Jeff Robbins ([@jeff17robbins](https://github.com/jeff17robbins)) +- João Neves ([@joaompneves](https://github.com/joaompneves)) - Joe Frayne ([@jfrayne](https://github.com/jfrayne)) - Joe Lidbetter ([@jmlidbetter](https://github.com/jmlidbetter)) - Joe Savage ([@s4v4g3](https://github.com/s4v4g3)) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6cc52d72..13ed9b331 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,10 +9,12 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. ### Added +- Added `ToPythonAs()` extension method to allow for explicit conversion using a specific type not known at build time. ([#2419][i2419]) + - Added `ToPythonAs()` extension method to allow for explicit conversion using a specific type. ([#2311][i2311]) - Added `IComparable` and `IEquatable` implementations to `PyInt`, `PyFloat`, and `PyString` - to compare with primitive .NET types like `long`. + to compare with primitive .NET types like `long`. ### Changed @@ -56,7 +58,6 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. - Fixed `PyInt` conversion to `BigInteger` and `System.String` produced incorrect result for values between 128 and 255. - Fixed implementing a generic interface with a Python class - ## [3.0.0](https://github.com/pythonnet/pythonnet/releases/tag/v3.0.0) - 2022-09-29 ### Added @@ -67,61 +68,63 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. - Ability to implement delegates with `ref` and `out` parameters in Python, by returning the modified parameter values in a tuple. ([#1355][i1355]) - Ability to override .NET methods that have `out` or `ref` in Python by returning the modified parameter values in a tuple. ([#1481][i1481]) - `PyType` - a wrapper for Python type objects, that also permits creating new heap types from `TypeSpec` -- Improved exception handling: - * exceptions can now be converted with codecs - * `InnerException` and `__cause__` are propagated properly +- Improved exception handling: + +* exceptions can now be converted with codecs +* `InnerException` and `__cause__` are propagated properly + - `__name__` and `__signature__` to reflected .NET methods - .NET collection types now implement standard Python collection interfaces from `collections.abc`. -See [Mixins/collections.py](src/runtime/Mixins/collections.py). + See [Mixins/collections.py](src/runtime/Mixins/collections.py). - you can cast objects to generic .NET interfaces without specifying generic arguments as long as there is no ambiguity. - .NET arrays implement Python buffer protocol - Python integer interoperability with `System.Numerics.BigInteger` - Python.NET will correctly resolve .NET methods, that accept `PyList`, `PyInt`, -and other `PyObject` derived types when called from Python. + and other `PyObject` derived types when called from Python. - .NET classes, that have `__call__` method are callable from Python - `PyIterable` type, that wraps any iterable object in Python - `PythonEngine` properties for supported Python versions: `MinSupportedVersion`, `MaxSupportedVersion`, and `IsSupportedVersion` - The runtime that is loaded on `import clr` can now be configured via environment variables - ### Changed + - Drop support for Python 2, 3.4, 3.5, and 3.6 - `wchar_t` size aka `Runtime.UCS` is now determined at runtime - `clr.AddReference` may now throw errors besides `FileNotFoundException`, that provide more -details about the cause of the failure + details about the cause of the failure - `clr.AddReference` no longer adds ".dll" implicitly - `PyIter(PyObject)` constructor replaced with static `PyIter.GetIter(PyObject)` method - Python runtime can no longer be shut down if the Python error indicator is set, as it would have unpredictable behavior - BREAKING: Return values from .NET methods that return an interface are now automatically - wrapped in that interface. This is a breaking change for users that rely on being - able to access members that are part of the implementation class, but not the - interface. Use the new `__implementation__` or `__raw_implementation__` properties to - if you need to "downcast" to the implementation class. + wrapped in that interface. This is a breaking change for users that rely on being + able to access members that are part of the implementation class, but not the + interface. Use the new `__implementation__` or `__raw_implementation__` properties to + if you need to "downcast" to the implementation class. - BREAKING: `==` and `!=` operators on `PyObject` instances now use Python comparison - (previously was equivalent to `object.ReferenceEquals(,)`) + (previously was equivalent to `object.ReferenceEquals(,)`) - BREAKING: Parameters marked with `ParameterAttributes.Out` are no longer returned in addition - to the regular method return value (unless they are passed with `ref` or `out` keyword). -- BREAKING: Drop support for the long-deprecated CLR.* prefix. + to the regular method return value (unless they are passed with `ref` or `out` keyword). +- BREAKING: Drop support for the long-deprecated CLR.\* prefix. - `PyObject` now implements `IEnumerable` in addition to `IEnumerable` - floating point values passed from Python are no longer silently truncated -when .NET expects an integer [#1342][i1342] + when .NET expects an integer [#1342][i1342] - More specific error messages for method argument mismatch - members of `PyObject` inherited from `System.Object and `DynamicObject` now autoacquire GIL - BREAKING: when inheriting from .NET types in Python if you override `__init__` you -must explicitly call base constructor using `super().__init__(.....)`. Not doing so will lead -to undefined behavior. + must explicitly call base constructor using `super().__init__(.....)`. Not doing so will lead + to undefined behavior. - BREAKING: most `PyScope` methods will never return `null`. Instead, `PyObject` `None` will be returned. - BREAKING: `PyScope` was renamed to `PyModule` - BREAKING: Methods with `ref` or `out` parameters and void return type return a tuple of only the `ref` and `out` parameters. - BREAKING: to call Python from .NET `Runtime.PythonDLL` property must be set to Python DLL name -or the DLL must be loaded in advance. This must be done before calling any other Python.NET functions. + or the DLL must be loaded in advance. This must be done before calling any other Python.NET functions. - BREAKING: `PyObject.Length()` now raises a `PythonException` when object does not support a concept of length. - BREAKING: disabled implicit conversion from C# enums to Python `int` and back. -One must now either use enum members (e.g. `MyEnum.Option`), or use enum constructor -(e.g. `MyEnum(42)` or `MyEnum(42, True)` when `MyEnum` does not have a member with value 42). + One must now either use enum members (e.g. `MyEnum.Option`), or use enum constructor + (e.g. `MyEnum(42)` or `MyEnum(42, True)` when `MyEnum` does not have a member with value 42). - BREAKING: disabled implicit conversion from Python objects implementing sequence protocol to -.NET arrays when the target .NET type is `System.Object`. The conversion is still attempted when the -target type is a `System.Array`. + .NET arrays when the target .NET type is `System.Object`. The conversion is still attempted when the + target type is a `System.Array`. - Sign Runtime DLL with a strong name - Implement loading through `clr_loader` instead of the included `ClrModule`, enables support for .NET Core @@ -131,23 +134,23 @@ target type is a `System.Array`. - Replaced the old `__import__` hook hack with a PEP302-style Meta Path Loader - BREAKING: Names of .NET types (e.g. `str(__class__)`) changed to better support generic types - BREAKING: overload resolution will no longer prefer basic types. Instead, first matching overload will -be chosen. + be chosen. - BREAKING: acquiring GIL using `Py.GIL` no longer forces `PythonEngine` to initialize - BREAKING: `Exec` and `Eval` from `PythonEngine` no longer accept raw pointers. - BREAKING: .NET collections and arrays are no longer automatically converted to -Python collections. Instead, they implement standard Python -collection interfaces from `collections.abc`. -See [Mixins/collections.py](src/runtime/Mixins/collections.py). + Python collections. Instead, they implement standard Python + collection interfaces from `collections.abc`. + See [Mixins/collections.py](src/runtime/Mixins/collections.py). - BREAKING: When trying to convert Python `int` to `System.Object`, result will -be of type `PyInt` instead of `System.Int32` due to possible loss of information. -Python `float` will continue to be converted to `System.Double`. + be of type `PyInt` instead of `System.Int32` due to possible loss of information. + Python `float` will continue to be converted to `System.Double`. - BREAKING: Python.NET will no longer implicitly convert types like `numpy.float64`, that implement `__float__` to -`System.Single` and `System.Double`. An explicit conversion is required on Python or .NET side. + `System.Single` and `System.Double`. An explicit conversion is required on Python or .NET side. - BREAKING: `PyObject.GetHashCode` can fail. - BREAKING: Python.NET will no longer implicitly convert any Python object to `System.Boolean`. - BREAKING: `PyObject.GetAttr(name, default)` now only ignores `AttributeError` (previously ignored all exceptions). - BREAKING: `PyObject` no longer implements `IEnumerable`. -Instead, `PyIterable` does that. + Instead, `PyIterable` does that. - BREAKING: `IPyObjectDecoder.CanDecode` `objectType` parameter type changed from `PyObject` to `PyType` ### Fixed @@ -179,18 +182,19 @@ Instead, `PyIterable` does that. ### Removed - `ShutdownMode` has been removed. The only shutdown mode supported now is an equivalent of `ShutdownMode.Reload`. -There is no need to specify it. + There is no need to specify it. - implicit assembly loading (you have to explicitly `clr.AddReference` before doing import) - messages in `PythonException` no longer start with exception type - `PyScopeManager`, `PyScopeException`, `PyScope` (use `PyModule` instead) - support for .NET Framework 4.0-4.6; Mono before 5.4. Python.NET now requires .NET Standard 2.0 -(see [the matrix](https://docs.microsoft.com/en-us/dotnet/standard/net-standard#net-implementation-support)) + (see [the matrix](https://docs.microsoft.com/en-us/dotnet/standard/net-standard#net-implementation-support)) ## [2.5.2](https://github.com/pythonnet/pythonnet/releases/tag/v2.5.2) - 2021-02-05 Bugfix release. ### Fixed + - Fix `object[]` parameters taking precedence when should not in overload resolution - Empty parameter names (as can be generated from F#) do not cause crashes @@ -200,8 +204,8 @@ Bugfix release. ### Fixed -- Fix incorrect dereference of wrapper object in `tp_repr`, which may result in a program crash -- Fix incorrect dereference in params array handling +- Fix incorrect dereference of wrapper object in `tp_repr`, which may result in a program crash +- Fix incorrect dereference in params array handling ## [2.5.0](https://github.com/pythonnet/pythonnet/releases/tag/v2.5.0) - 2020-06-14 @@ -308,7 +312,6 @@ This version improves performance on benchmarks significantly compared to 2.3. - Fix spurious assembly loading exceptions from private types ([#703][i703]) - Fix inheritance of non-abstract base methods ([#755][i755]) - ## [2.3.0][] - 2017-03-11 ### Added @@ -845,25 +848,15 @@ This version improves performance on benchmarks significantly compared to 2.3. - Initial (mostly) working experimental release. [keep a changelog]: http://keepachangelog.com/ - [semantic versioning]: http://semver.org/ - [unreleased]: ../../compare/v3.0.1...HEAD - [2.3.0]: ../../compare/v2.2.2...v2.3.0 - [2.2.2]: ../../compare/v2.2.1...v2.2.2 - [2.2.1]: ../../compare/v2.2.0-dev1...v2.2.1 - [2.2.0-dev1]: ../../compare/v2.1.0...v2.2.0-dev1 - [2.1.0]: ../../compare/v2.0.0...v2.1.0 - [2.0.0]: ../../compare/1.0...v2.0.0 - [1.0.0]: https://github.com/pythonnet/pythonnet/releases/tag/1.0 - [i714]: https://github.com/pythonnet/pythonnet/issues/714 [i608]: https://github.com/pythonnet/pythonnet/issues/608 [i443]: https://github.com/pythonnet/pythonnet/issues/443 From b5a18d1b125ec838cd215090aabd7ca83932cf94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Neves?= Date: Thu, 18 Jul 2024 18:13:09 +0100 Subject: [PATCH 08/12] Update CHANGELOG.md Revert unintentional changes --- CHANGELOG.md | 90 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 52 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13ed9b331..1930fe9d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,13 +14,18 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. - Added `ToPythonAs()` extension method to allow for explicit conversion using a specific type. ([#2311][i2311]) - Added `IComparable` and `IEquatable` implementations to `PyInt`, `PyFloat`, and `PyString` - to compare with primitive .NET types like `long`. + to compare with primitive .NET types like `long`. ### Changed +- Added a `FormatterFactory` member in RuntimeData to create formatters with parameters. For compatibility, the `FormatterType` member is still present and has precedence when defining both `FormatterFactory` and `FormatterType` +- Added a post-serialization and a pre-deserialization step callbacks to extend (de)serialization process +- Added an API to stash serialized data on Python capsules ### Fixed - Fixed RecursionError for reverse operators on C# operable types from python. See #2240 +- Fixed crash when .NET event has no `AddMethod` +- Fixed probing for assemblies in `sys.path` failing when a path in `sys.path` has invalid characters. See #2376 ## [3.0.3](https://github.com/pythonnet/pythonnet/releases/tag/v3.0.3) - 2023-10-11 @@ -58,6 +63,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. - Fixed `PyInt` conversion to `BigInteger` and `System.String` produced incorrect result for values between 128 and 255. - Fixed implementing a generic interface with a Python class + ## [3.0.0](https://github.com/pythonnet/pythonnet/releases/tag/v3.0.0) - 2022-09-29 ### Added @@ -68,63 +74,61 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. - Ability to implement delegates with `ref` and `out` parameters in Python, by returning the modified parameter values in a tuple. ([#1355][i1355]) - Ability to override .NET methods that have `out` or `ref` in Python by returning the modified parameter values in a tuple. ([#1481][i1481]) - `PyType` - a wrapper for Python type objects, that also permits creating new heap types from `TypeSpec` -- Improved exception handling: - -* exceptions can now be converted with codecs -* `InnerException` and `__cause__` are propagated properly - +- Improved exception handling: + * exceptions can now be converted with codecs + * `InnerException` and `__cause__` are propagated properly - `__name__` and `__signature__` to reflected .NET methods - .NET collection types now implement standard Python collection interfaces from `collections.abc`. - See [Mixins/collections.py](src/runtime/Mixins/collections.py). +See [Mixins/collections.py](src/runtime/Mixins/collections.py). - you can cast objects to generic .NET interfaces without specifying generic arguments as long as there is no ambiguity. - .NET arrays implement Python buffer protocol - Python integer interoperability with `System.Numerics.BigInteger` - Python.NET will correctly resolve .NET methods, that accept `PyList`, `PyInt`, - and other `PyObject` derived types when called from Python. +and other `PyObject` derived types when called from Python. - .NET classes, that have `__call__` method are callable from Python - `PyIterable` type, that wraps any iterable object in Python - `PythonEngine` properties for supported Python versions: `MinSupportedVersion`, `MaxSupportedVersion`, and `IsSupportedVersion` - The runtime that is loaded on `import clr` can now be configured via environment variables -### Changed +### Changed - Drop support for Python 2, 3.4, 3.5, and 3.6 - `wchar_t` size aka `Runtime.UCS` is now determined at runtime - `clr.AddReference` may now throw errors besides `FileNotFoundException`, that provide more - details about the cause of the failure +details about the cause of the failure - `clr.AddReference` no longer adds ".dll" implicitly - `PyIter(PyObject)` constructor replaced with static `PyIter.GetIter(PyObject)` method - Python runtime can no longer be shut down if the Python error indicator is set, as it would have unpredictable behavior - BREAKING: Return values from .NET methods that return an interface are now automatically - wrapped in that interface. This is a breaking change for users that rely on being - able to access members that are part of the implementation class, but not the - interface. Use the new `__implementation__` or `__raw_implementation__` properties to - if you need to "downcast" to the implementation class. + wrapped in that interface. This is a breaking change for users that rely on being + able to access members that are part of the implementation class, but not the + interface. Use the new `__implementation__` or `__raw_implementation__` properties to + if you need to "downcast" to the implementation class. - BREAKING: `==` and `!=` operators on `PyObject` instances now use Python comparison - (previously was equivalent to `object.ReferenceEquals(,)`) + (previously was equivalent to `object.ReferenceEquals(,)`) - BREAKING: Parameters marked with `ParameterAttributes.Out` are no longer returned in addition - to the regular method return value (unless they are passed with `ref` or `out` keyword). -- BREAKING: Drop support for the long-deprecated CLR.\* prefix. + to the regular method return value (unless they are passed with `ref` or `out` keyword). +- BREAKING: Drop support for the long-deprecated CLR.* prefix. - `PyObject` now implements `IEnumerable` in addition to `IEnumerable` - floating point values passed from Python are no longer silently truncated - when .NET expects an integer [#1342][i1342] +when .NET expects an integer [#1342][i1342] - More specific error messages for method argument mismatch - members of `PyObject` inherited from `System.Object and `DynamicObject` now autoacquire GIL - BREAKING: when inheriting from .NET types in Python if you override `__init__` you - must explicitly call base constructor using `super().__init__(.....)`. Not doing so will lead - to undefined behavior. +must explicitly call base constructor using `super().__init__(.....)`. Not doing so will lead +to undefined behavior. - BREAKING: most `PyScope` methods will never return `null`. Instead, `PyObject` `None` will be returned. - BREAKING: `PyScope` was renamed to `PyModule` - BREAKING: Methods with `ref` or `out` parameters and void return type return a tuple of only the `ref` and `out` parameters. - BREAKING: to call Python from .NET `Runtime.PythonDLL` property must be set to Python DLL name - or the DLL must be loaded in advance. This must be done before calling any other Python.NET functions. +or the DLL must be loaded in advance. This must be done before calling any other Python.NET functions. - BREAKING: `PyObject.Length()` now raises a `PythonException` when object does not support a concept of length. - BREAKING: disabled implicit conversion from C# enums to Python `int` and back. - One must now either use enum members (e.g. `MyEnum.Option`), or use enum constructor - (e.g. `MyEnum(42)` or `MyEnum(42, True)` when `MyEnum` does not have a member with value 42). +One must now either use enum members (e.g. `MyEnum.Option`), or use enum constructor +(e.g. `MyEnum(42)` or `MyEnum(42, True)` when `MyEnum` does not have a member with value 42). - BREAKING: disabled implicit conversion from Python objects implementing sequence protocol to - .NET arrays when the target .NET type is `System.Object`. The conversion is still attempted when the - target type is a `System.Array`. +.NET arrays when the target .NET type is `System.Object`. The conversion is still attempted when the +target type is a `System.Array`. - Sign Runtime DLL with a strong name - Implement loading through `clr_loader` instead of the included `ClrModule`, enables support for .NET Core @@ -134,23 +138,23 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. - Replaced the old `__import__` hook hack with a PEP302-style Meta Path Loader - BREAKING: Names of .NET types (e.g. `str(__class__)`) changed to better support generic types - BREAKING: overload resolution will no longer prefer basic types. Instead, first matching overload will - be chosen. +be chosen. - BREAKING: acquiring GIL using `Py.GIL` no longer forces `PythonEngine` to initialize - BREAKING: `Exec` and `Eval` from `PythonEngine` no longer accept raw pointers. - BREAKING: .NET collections and arrays are no longer automatically converted to - Python collections. Instead, they implement standard Python - collection interfaces from `collections.abc`. - See [Mixins/collections.py](src/runtime/Mixins/collections.py). +Python collections. Instead, they implement standard Python +collection interfaces from `collections.abc`. +See [Mixins/collections.py](src/runtime/Mixins/collections.py). - BREAKING: When trying to convert Python `int` to `System.Object`, result will - be of type `PyInt` instead of `System.Int32` due to possible loss of information. - Python `float` will continue to be converted to `System.Double`. +be of type `PyInt` instead of `System.Int32` due to possible loss of information. +Python `float` will continue to be converted to `System.Double`. - BREAKING: Python.NET will no longer implicitly convert types like `numpy.float64`, that implement `__float__` to - `System.Single` and `System.Double`. An explicit conversion is required on Python or .NET side. +`System.Single` and `System.Double`. An explicit conversion is required on Python or .NET side. - BREAKING: `PyObject.GetHashCode` can fail. - BREAKING: Python.NET will no longer implicitly convert any Python object to `System.Boolean`. - BREAKING: `PyObject.GetAttr(name, default)` now only ignores `AttributeError` (previously ignored all exceptions). - BREAKING: `PyObject` no longer implements `IEnumerable`. - Instead, `PyIterable` does that. +Instead, `PyIterable` does that. - BREAKING: `IPyObjectDecoder.CanDecode` `objectType` parameter type changed from `PyObject` to `PyType` ### Fixed @@ -182,19 +186,18 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. ### Removed - `ShutdownMode` has been removed. The only shutdown mode supported now is an equivalent of `ShutdownMode.Reload`. - There is no need to specify it. +There is no need to specify it. - implicit assembly loading (you have to explicitly `clr.AddReference` before doing import) - messages in `PythonException` no longer start with exception type - `PyScopeManager`, `PyScopeException`, `PyScope` (use `PyModule` instead) - support for .NET Framework 4.0-4.6; Mono before 5.4. Python.NET now requires .NET Standard 2.0 - (see [the matrix](https://docs.microsoft.com/en-us/dotnet/standard/net-standard#net-implementation-support)) +(see [the matrix](https://docs.microsoft.com/en-us/dotnet/standard/net-standard#net-implementation-support)) ## [2.5.2](https://github.com/pythonnet/pythonnet/releases/tag/v2.5.2) - 2021-02-05 Bugfix release. ### Fixed - - Fix `object[]` parameters taking precedence when should not in overload resolution - Empty parameter names (as can be generated from F#) do not cause crashes @@ -204,8 +207,8 @@ Bugfix release. ### Fixed -- Fix incorrect dereference of wrapper object in `tp_repr`, which may result in a program crash -- Fix incorrect dereference in params array handling +- Fix incorrect dereference of wrapper object in `tp_repr`, which may result in a program crash +- Fix incorrect dereference in params array handling ## [2.5.0](https://github.com/pythonnet/pythonnet/releases/tag/v2.5.0) - 2020-06-14 @@ -312,6 +315,7 @@ This version improves performance on benchmarks significantly compared to 2.3. - Fix spurious assembly loading exceptions from private types ([#703][i703]) - Fix inheritance of non-abstract base methods ([#755][i755]) + ## [2.3.0][] - 2017-03-11 ### Added @@ -848,15 +852,25 @@ This version improves performance on benchmarks significantly compared to 2.3. - Initial (mostly) working experimental release. [keep a changelog]: http://keepachangelog.com/ + [semantic versioning]: http://semver.org/ + [unreleased]: ../../compare/v3.0.1...HEAD + [2.3.0]: ../../compare/v2.2.2...v2.3.0 + [2.2.2]: ../../compare/v2.2.1...v2.2.2 + [2.2.1]: ../../compare/v2.2.0-dev1...v2.2.1 + [2.2.0-dev1]: ../../compare/v2.1.0...v2.2.0-dev1 + [2.1.0]: ../../compare/v2.0.0...v2.1.0 + [2.0.0]: ../../compare/1.0...v2.0.0 + [1.0.0]: https://github.com/pythonnet/pythonnet/releases/tag/1.0 + [i714]: https://github.com/pythonnet/pythonnet/issues/714 [i608]: https://github.com/pythonnet/pythonnet/issues/608 [i443]: https://github.com/pythonnet/pythonnet/issues/443 From 37ec583443f740fcbd73e2bc52d5e06c8a693b3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Neves?= Date: Thu, 18 Jul 2024 18:14:38 +0100 Subject: [PATCH 09/12] Update CHANGELOG.md --- CHANGELOG.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1930fe9d5..4ec8ee287 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,14 +17,9 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. to compare with primitive .NET types like `long`. ### Changed -- Added a `FormatterFactory` member in RuntimeData to create formatters with parameters. For compatibility, the `FormatterType` member is still present and has precedence when defining both `FormatterFactory` and `FormatterType` -- Added a post-serialization and a pre-deserialization step callbacks to extend (de)serialization process -- Added an API to stash serialized data on Python capsules ### Fixed -- Fixed RecursionError for reverse operators on C# operable types from python. See #2240 -- Fixed crash when .NET event has no `AddMethod` - Fixed probing for assemblies in `sys.path` failing when a path in `sys.path` has invalid characters. See #2376 ## [3.0.3](https://github.com/pythonnet/pythonnet/releases/tag/v3.0.3) - 2023-10-11 From ad7f9857f6389d5445c0283b2e7c24606d744159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Neves?= Date: Thu, 18 Jul 2024 18:15:19 +0100 Subject: [PATCH 10/12] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ec8ee287..9103d5a33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. ### Fixed -- Fixed probing for assemblies in `sys.path` failing when a path in `sys.path` has invalid characters. See #2376 +- Fixed RecursionError for reverse operators on C# operable types from python. See #2240 ## [3.0.3](https://github.com/pythonnet/pythonnet/releases/tag/v3.0.3) - 2023-10-11 From bac598fa1d64d4b9d44514689b62e7d5d5b321e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joa=CC=83o=20Neves?= Date: Tue, 23 Jul 2024 10:45:25 +0100 Subject: [PATCH 11/12] CR --- src/runtime/Converter.cs | 3 +-- src/runtime/PythonTypes/PyObject.cs | 5 +++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/runtime/Converter.cs b/src/runtime/Converter.cs index a1b5703a5..d31614067 100644 --- a/src/runtime/Converter.cs +++ b/src/runtime/Converter.cs @@ -984,8 +984,7 @@ public static PyObject ToPython(this object? o) public static PyObject ToPythonAs(this T? o) { - if (o is null) return Runtime.None; - return Converter.ToPython(o, typeof(T)).MoveToPyObject(); + return ToPythonAs(o, typeof(T)); } public static PyObject ToPythonAs(this object? o, Type type) diff --git a/src/runtime/PythonTypes/PyObject.cs b/src/runtime/PythonTypes/PyObject.cs index a62f92ee7..f560be343 100644 --- a/src/runtime/PythonTypes/PyObject.cs +++ b/src/runtime/PythonTypes/PyObject.cs @@ -136,14 +136,14 @@ public IntPtr Handle /// Given an arbitrary managed object, return a Python instance that /// reflects the managed object. /// - public static PyObject FromManagedObject(object ob, Type? type = null) + public static PyObject FromManagedObject(object ob) { // Special case: if ob is null, we return None. if (ob == null) { return new PyObject(Runtime.PyNone); } - return CLRObject.GetReference(ob, type ?? ob.GetType()).MoveToPyObject(); + return CLRObject.GetReference(ob).MoveToPyObject(); } /// @@ -235,6 +235,7 @@ public void Dispose() { GC.SuppressFinalize(this); Dispose(true); + } internal StolenReference Steal() From 8bb75194671cb9e9a90eb4b4de00576da1a75131 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joa=CC=83o=20Neves?= Date: Tue, 23 Jul 2024 10:49:00 +0100 Subject: [PATCH 12/12] Revert file --- src/runtime/PythonTypes/PyObject.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/PythonTypes/PyObject.cs b/src/runtime/PythonTypes/PyObject.cs index f560be343..cf0c2a03f 100644 --- a/src/runtime/PythonTypes/PyObject.cs +++ b/src/runtime/PythonTypes/PyObject.cs @@ -25,7 +25,7 @@ public partial class PyObject : DynamicObject, IDisposable, ISerializable /// Trace stack for PyObject's construction /// public StackTrace Traceback { get; } = new StackTrace(1); -#endif +#endif protected IntPtr rawPtr = IntPtr.Zero; internal readonly int run = Runtime.GetRun(); @@ -235,7 +235,7 @@ public void Dispose() { GC.SuppressFinalize(this); Dispose(true); - + } internal StolenReference Steal() pFad - Phonifier reborn

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

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


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy