From d9c326cd2bfb6941d435b6f1ed03ec4a11bca5e0 Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Mon, 18 Sep 2023 07:44:32 -0500 Subject: [PATCH 1/8] 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 cc42039e8..ffbe13dda 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 f24f95b36..b7af47c8e 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 3acd1ca1b20fda3675dbeaff16c54285e60f80eb Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Mon, 18 Sep 2023 07:57:59 -0500 Subject: [PATCH 2/8] 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 b7af47c8e..dc6399ac1 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 be2ae6712d782b5cda84d088b1b0d77f5bee6bb7 Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Mon, 18 Sep 2023 07:58:44 -0500 Subject: [PATCH 3/8] changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ba0b935c..fb13982e6 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 dea66fb18013bb4ab93878f7c4ad135888ebf2ef Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Tue, 19 Sep 2023 09:35:21 -0500 Subject: [PATCH 4/8] 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 ffbe13dda..b15ef7e2a 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 dc6399ac1..acd6f6b78 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 a3be4813cf2354ab00cef6d6f438c6d2966f5619 Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Tue, 19 Sep 2023 09:57:11 -0500 Subject: [PATCH 5/8] 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 acd6f6b78..0873ab592 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 5133cefa521553c670232d9a6bf803d6fc0dd531 Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Thu, 21 Sep 2023 10:40:46 -0500 Subject: [PATCH 6/8] 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 b15ef7e2a..a24265fc4 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 0873ab592..9d8565084 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 6e70b0eaa06a19b17d7e512218aa38cacebe9b80 Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Thu, 21 Sep 2023 10:57:59 -0500 Subject: [PATCH 7/8] 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 9d8565084..3d3edba10 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 22745953d49c999a8052ce4fa747bf6c6cca4e8a Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Fri, 22 Sep 2023 09:02:40 -0500 Subject: [PATCH 8/8] 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 a24265fc4..f0585ffa6 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);