From 85801e0eb6f59a3dc9c9e1ea26c1f1918260558a Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Mon, 18 Sep 2023 07:44:32 -0500 Subject: [PATCH 1/9] use enum name in repr --- src/runtime/Types/ClassObject.cs | 21 +++++++++++++++++++++ tests/test_enum.py | 7 +++++++ 2 files changed, 28 insertions(+) diff --git a/src/runtime/Types/ClassObject.cs b/src/runtime/Types/ClassObject.cs index cc42039e..ffbe13dd 100644 --- a/src/runtime/Types/ClassObject.cs +++ b/src/runtime/Types/ClassObject.cs @@ -48,6 +48,27 @@ internal NewReference GetDocString() } + /// + /// ClassObject __repr__ implementation. + /// + public new static NewReference tp_repr(BorrowedReference ob) + { + if (GetManagedObject(ob) is not CLRObject co) + { + return Exceptions.RaiseTypeError("invalid object"); + } + + var inst = co.inst; + var obType = inst.GetType(); + if (obType.IsEnum) + { + var repr = string.Format("{0}.{1}", obType.Name, inst.ToString()); + return Runtime.PyString_FromString(repr); + } + + return ClassBase.tp_repr(ob); + } + /// /// Implements __new__ for reflected classes and value types. /// diff --git a/tests/test_enum.py b/tests/test_enum.py index f24f95b3..b7af47c8 100644 --- a/tests/test_enum.py +++ b/tests/test_enum.py @@ -143,6 +143,13 @@ def test_enum_undefined_value(): Test.FieldTest().EnumField = Test.ShortEnum(20, True) +def test_enum_repr(): + """Test enumeration repr.""" + from System import DayOfWeek + + assert repr(DayOfWeek.Monday) == "Monday" + + def test_enum_conversion(): """Test enumeration conversion.""" ob = Test.FieldTest() From 2044846dd6c637cbf6bd59ce806e591d1b3d66e0 Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Mon, 18 Sep 2023 07:57:59 -0500 Subject: [PATCH 2/9] update test --- tests/test_enum.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_enum.py b/tests/test_enum.py index b7af47c8..dc6399ac 100644 --- a/tests/test_enum.py +++ b/tests/test_enum.py @@ -147,7 +147,7 @@ def test_enum_repr(): """Test enumeration repr.""" from System import DayOfWeek - assert repr(DayOfWeek.Monday) == "Monday" + assert repr(DayOfWeek.Monday) == "DayOfWeek.Monday" def test_enum_conversion(): From 0fe95b234ea88b097d6a56ec586ad4267e554ada Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Mon, 18 Sep 2023 07:58:44 -0500 Subject: [PATCH 3/9] changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2347895a..35962b4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. ### Added +- use enum name in repr + ### Changed ### Fixed From 321c45271c9501e367ce2eab41a7c9efe492007b Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Tue, 19 Sep 2023 09:35:21 -0500 Subject: [PATCH 4/9] Use python convention --- src/runtime/Types/ClassObject.cs | 28 ++++++++++++++++++++++------ tests/test_enum.py | 5 ++++- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/runtime/Types/ClassObject.cs b/src/runtime/Types/ClassObject.cs index ffbe13dd..b15ef7e2 100644 --- a/src/runtime/Types/ClassObject.cs +++ b/src/runtime/Types/ClassObject.cs @@ -48,6 +48,26 @@ internal NewReference GetDocString() } + /// + /// given an enum, write a __repr__ string formatted in the same + /// way as a python repr string. Something like: + /// '<Color.GREEN: 2>'; + /// with a binary value for [Flags] enums + /// + /// Instace of the enum object + /// + private static string getEnumReprString(object inst) + { + var obType = inst.GetType(); + + var isFlags = obType.IsFlagsEnum(); + var intValue = Convert.ToInt32(inst); + var intStr = isFlags ? "0x" + intValue.ToString("X4") : intValue.ToString(); + + var repr = $"<{obType.Name}.{inst}: {intStr}>"; + return repr; + } + /// /// ClassObject __repr__ implementation. /// @@ -57,13 +77,9 @@ internal NewReference GetDocString() { return Exceptions.RaiseTypeError("invalid object"); } - - var inst = co.inst; - var obType = inst.GetType(); - if (obType.IsEnum) + if (co.inst.GetType().IsEnum) { - var repr = string.Format("{0}.{1}", obType.Name, inst.ToString()); - return Runtime.PyString_FromString(repr); + return Runtime.PyString_FromString(getEnumReprString(co.inst)); } return ClassBase.tp_repr(ob); diff --git a/tests/test_enum.py b/tests/test_enum.py index dc6399ac..acd6f6b7 100644 --- a/tests/test_enum.py +++ b/tests/test_enum.py @@ -147,7 +147,10 @@ def test_enum_repr(): """Test enumeration repr.""" from System import DayOfWeek - assert repr(DayOfWeek.Monday) == "DayOfWeek.Monday" + assert repr(DayOfWeek.Monday) == "" + + flags_value = Test.FlagsEnum.One | Test.FlagsEnum.Two + assert repr(flags_value) == "" def test_enum_conversion(): From 6cb8d0ca2df3f66d19640b79da6d173e822f2508 Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Tue, 19 Sep 2023 09:57:11 -0500 Subject: [PATCH 5/9] fix test --- tests/test_enum.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_enum.py b/tests/test_enum.py index acd6f6b7..0873ab59 100644 --- a/tests/test_enum.py +++ b/tests/test_enum.py @@ -149,8 +149,8 @@ def test_enum_repr(): assert repr(DayOfWeek.Monday) == "" - flags_value = Test.FlagsEnum.One | Test.FlagsEnum.Two - assert repr(flags_value) == "" + assert repr(Test.FlagsEnum(7)) == "" + assert repr(Test.FlagsEnum(8)) == "" def test_enum_conversion(): From 48367fcea823ef25a9811795e21e4e6f22a95792 Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Thu, 21 Sep 2023 10:40:46 -0500 Subject: [PATCH 6/9] respect base enum type --- src/runtime/Types/ClassObject.cs | 45 +++++++++++++++++++++++++++++--- tests/test_enum.py | 2 +- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/runtime/Types/ClassObject.cs b/src/runtime/Types/ClassObject.cs index b15ef7e2..a24265fc 100644 --- a/src/runtime/Types/ClassObject.cs +++ b/src/runtime/Types/ClassObject.cs @@ -60,11 +60,50 @@ private static string getEnumReprString(object inst) { var obType = inst.GetType(); + var integralType = obType.GetEnumUnderlyingType(); var isFlags = obType.IsFlagsEnum(); - var intValue = Convert.ToInt32(inst); - var intStr = isFlags ? "0x" + intValue.ToString("X4") : intValue.ToString(); - var repr = $"<{obType.Name}.{inst}: {intStr}>"; + string strValue = ""; + switch (Type.GetTypeCode(integralType)) + { + case TypeCode.SByte: + var valueSB = Convert.ToSByte(inst); + strValue = isFlags ? "0x" + valueSB.ToString("X2") : valueSB.ToString(); + break; + case TypeCode.Byte: + var valueB = Convert.ToByte(inst); + strValue = isFlags ? "0x" + valueB.ToString("X2") : valueB.ToString(); + break; + case TypeCode.Int16: + var valueI16 = Convert.ToInt16(inst); + strValue = isFlags ? "0x" + valueI16.ToString("X4") : valueI16.ToString(); + break; + case TypeCode.UInt16: + var valueUI16 = Convert.ToUInt16(inst); + strValue = isFlags ? "0x" + valueUI16.ToString("X4") : valueUI16.ToString(); + break; + case TypeCode.Int32: + var valueI32 = Convert.ToInt32(inst); + strValue = isFlags ? "0x" + valueI32.ToString("X8") : valueI32.ToString(); + break; + case TypeCode.UInt32: + var valueUI32 = Convert.ToUInt32(inst); + strValue = isFlags ? "0x" + valueUI32.ToString("X8") : valueUI32.ToString(); + break; + case TypeCode.Int64: + var valueI64 = Convert.ToInt64(inst); + strValue = isFlags ? "0x" + valueI64.ToString("X16") : valueI64.ToString(); + break; + case TypeCode.UInt64: + var valueUI64 = Convert.ToUInt64(inst); + strValue = isFlags ? "0x" + valueUI64.ToString("X16") : valueUI64.ToString(); + break; + default: + break; + } + + + var repr = $"<{obType.Name}.{inst}: {strValue}>"; return repr; } diff --git a/tests/test_enum.py b/tests/test_enum.py index 0873ab59..9d856508 100644 --- a/tests/test_enum.py +++ b/tests/test_enum.py @@ -150,7 +150,7 @@ def test_enum_repr(): assert repr(DayOfWeek.Monday) == "" assert repr(Test.FlagsEnum(7)) == "" - assert repr(Test.FlagsEnum(8)) == "" + assert repr(Test.FlagsEnum(8)) == "" def test_enum_conversion(): From 9cdcb511c0dfa0c22f67c0146ff815c933ca7ddf Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Thu, 21 Sep 2023 10:57:59 -0500 Subject: [PATCH 7/9] fix other assert --- tests/test_enum.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_enum.py b/tests/test_enum.py index 9d856508..3d3edba1 100644 --- a/tests/test_enum.py +++ b/tests/test_enum.py @@ -149,7 +149,7 @@ def test_enum_repr(): assert repr(DayOfWeek.Monday) == "" - assert repr(Test.FlagsEnum(7)) == "" + assert repr(Test.FlagsEnum(7)) == "" assert repr(Test.FlagsEnum(8)) == "" From 6a98a89dc5a05f9b8dd4742bc6bf0816c836c567 Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Fri, 22 Sep 2023 09:02:40 -0500 Subject: [PATCH 8/9] refactor --- src/runtime/Types/ClassObject.cs | 65 ++++++++++---------------------- 1 file changed, 20 insertions(+), 45 deletions(-) diff --git a/src/runtime/Types/ClassObject.cs b/src/runtime/Types/ClassObject.cs index a24265fc..f0585ffa 100644 --- a/src/runtime/Types/ClassObject.cs +++ b/src/runtime/Types/ClassObject.cs @@ -1,7 +1,9 @@ using System; using System.Diagnostics; +using System.Globalization; using System.Linq; using System.Reflection; +using System.Runtime.InteropServices; using System.Runtime.Serialization; namespace Python.Runtime @@ -47,6 +49,20 @@ internal NewReference GetDocString() return Runtime.PyString_FromString(str); } + private static string ConvertFlags(Enum value) + { + Type primitiveType = value.GetType().GetEnumUnderlyingType(); + string format = "X" + (Marshal.SizeOf(primitiveType) * 2).ToString(CultureInfo.InvariantCulture); + var primitive = (IFormattable)Convert.ChangeType(value, primitiveType); + return "0x" + primitive.ToString(format, null); + + } + + private static string ConvertValue(Enum value) + { + Type primitiveType = value.GetType().GetEnumUnderlyingType(); + return Convert.ChangeType(value, primitiveType).ToString()!; + } /// /// given an enum, write a __repr__ string formatted in the same @@ -56,54 +72,13 @@ internal NewReference GetDocString() /// /// Instace of the enum object /// - private static string getEnumReprString(object inst) + private static string GetEnumReprString(Enum inst) { var obType = inst.GetType(); - var integralType = obType.GetEnumUnderlyingType(); - var isFlags = obType.IsFlagsEnum(); - - string strValue = ""; - switch (Type.GetTypeCode(integralType)) - { - case TypeCode.SByte: - var valueSB = Convert.ToSByte(inst); - strValue = isFlags ? "0x" + valueSB.ToString("X2") : valueSB.ToString(); - break; - case TypeCode.Byte: - var valueB = Convert.ToByte(inst); - strValue = isFlags ? "0x" + valueB.ToString("X2") : valueB.ToString(); - break; - case TypeCode.Int16: - var valueI16 = Convert.ToInt16(inst); - strValue = isFlags ? "0x" + valueI16.ToString("X4") : valueI16.ToString(); - break; - case TypeCode.UInt16: - var valueUI16 = Convert.ToUInt16(inst); - strValue = isFlags ? "0x" + valueUI16.ToString("X4") : valueUI16.ToString(); - break; - case TypeCode.Int32: - var valueI32 = Convert.ToInt32(inst); - strValue = isFlags ? "0x" + valueI32.ToString("X8") : valueI32.ToString(); - break; - case TypeCode.UInt32: - var valueUI32 = Convert.ToUInt32(inst); - strValue = isFlags ? "0x" + valueUI32.ToString("X8") : valueUI32.ToString(); - break; - case TypeCode.Int64: - var valueI64 = Convert.ToInt64(inst); - strValue = isFlags ? "0x" + valueI64.ToString("X16") : valueI64.ToString(); - break; - case TypeCode.UInt64: - var valueUI64 = Convert.ToUInt64(inst); - strValue = isFlags ? "0x" + valueUI64.ToString("X16") : valueUI64.ToString(); - break; - default: - break; - } - + string strValue2 = obType.IsFlagsEnum() ? ConvertFlags(inst) : ConvertValue(inst); - var repr = $"<{obType.Name}.{inst}: {strValue}>"; + var repr = $"<{obType.Name}.{inst}: {strValue2}>"; return repr; } @@ -118,7 +93,7 @@ private static string getEnumReprString(object inst) } if (co.inst.GetType().IsEnum) { - return Runtime.PyString_FromString(getEnumReprString(co.inst)); + return Runtime.PyString_FromString(GetEnumReprString((Enum)co.inst)); } return ClassBase.tp_repr(ob); From 5cb63967d3fb637b4e6104db8698225f9d8d1908 Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Mon, 25 Sep 2023 11:53:36 -0500 Subject: [PATCH 9/9] readme update --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index ee77f6c6..00d4c722 100644 --- a/README.rst +++ b/README.rst @@ -4,3 +4,4 @@ We will try to keep this up-to-date with pythonnet and upstream changes that mig Changes relative to pythonnet: - Revert of `#1240 `_. +- Enum REPR `#2239 ` is included in this release of version 3.0.2, but is unreleased in pythonnet \ No newline at end of file