diff --git a/src/perf_tests/Python.PerformanceTests.csproj b/src/perf_tests/Python.PerformanceTests.csproj
index 4ee604bf2..8ea99d9b2 100644
--- a/src/perf_tests/Python.PerformanceTests.csproj
+++ b/src/perf_tests/Python.PerformanceTests.csproj
@@ -13,7 +13,7 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
compile
@@ -25,7 +25,7 @@
-
+
diff --git a/src/runtime/ClassManager.cs b/src/runtime/ClassManager.cs
index bf852112c..b88a6a6b6 100644
--- a/src/runtime/ClassManager.cs
+++ b/src/runtime/ClassManager.cs
@@ -220,6 +220,11 @@ internal static ClassBase CreateClass(Type type)
impl = new LookUpObject(type);
}
+ else if (type.IsEnum)
+ {
+ impl = new EnumObject(type);
+ }
+
else
{
impl = new ClassObject(type);
diff --git a/src/runtime/Properties/AssemblyInfo.cs b/src/runtime/Properties/AssemblyInfo.cs
index a7c2c1a3d..4bada6682 100644
--- a/src/runtime/Properties/AssemblyInfo.cs
+++ b/src/runtime/Properties/AssemblyInfo.cs
@@ -4,5 +4,5 @@
[assembly: InternalsVisibleTo("Python.EmbeddingTest, PublicKey=00240000048000009400000006020000002400005253413100040000110000005ffd8f49fb44ab0641b3fd8d55e749f716e6dd901032295db641eb98ee46063cbe0d4a1d121ef0bc2af95f8a7438d7a80a3531316e6b75c2dae92fb05a99f03bf7e0c03980e1c3cfb74ba690aca2f3339ef329313bcc5dccced125a4ffdc4531dcef914602cd5878dc5fbb4d4c73ddfbc133f840231343e013762884d6143189")]
[assembly: InternalsVisibleTo("Python.Test, PublicKey=00240000048000009400000006020000002400005253413100040000110000005ffd8f49fb44ab0641b3fd8d55e749f716e6dd901032295db641eb98ee46063cbe0d4a1d121ef0bc2af95f8a7438d7a80a3531316e6b75c2dae92fb05a99f03bf7e0c03980e1c3cfb74ba690aca2f3339ef329313bcc5dccced125a4ffdc4531dcef914602cd5878dc5fbb4d4c73ddfbc133f840231343e013762884d6143189")]
-[assembly: AssemblyVersion("2.0.46")]
-[assembly: AssemblyFileVersion("2.0.46")]
+[assembly: AssemblyVersion("2.0.47")]
+[assembly: AssemblyFileVersion("2.0.47")]
diff --git a/src/runtime/Python.Runtime.csproj b/src/runtime/Python.Runtime.csproj
index 558466d26..b60b36e6b 100644
--- a/src/runtime/Python.Runtime.csproj
+++ b/src/runtime/Python.Runtime.csproj
@@ -5,7 +5,7 @@
Python.Runtime
Python.Runtime
QuantConnect.pythonnet
- 2.0.46
+ 2.0.47
false
LICENSE
https://github.com/pythonnet/pythonnet
diff --git a/src/runtime/Types/ClassBase.cs b/src/runtime/Types/ClassBase.cs
index ded315952..590c870b5 100644
--- a/src/runtime/Types/ClassBase.cs
+++ b/src/runtime/Types/ClassBase.cs
@@ -156,42 +156,7 @@ public static NewReference tp_richcompare(BorrowedReference ob, BorrowedReferenc
try
{
int cmp = co1Comp.CompareTo(co2Inst);
-
- BorrowedReference pyCmp;
- if (cmp < 0)
- {
- if (op == Runtime.Py_LT || op == Runtime.Py_LE)
- {
- pyCmp = Runtime.PyTrue;
- }
- else
- {
- pyCmp = Runtime.PyFalse;
- }
- }
- else if (cmp == 0)
- {
- if (op == Runtime.Py_LE || op == Runtime.Py_GE)
- {
- pyCmp = Runtime.PyTrue;
- }
- else
- {
- pyCmp = Runtime.PyFalse;
- }
- }
- else
- {
- if (op == Runtime.Py_GE || op == Runtime.Py_GT)
- {
- pyCmp = Runtime.PyTrue;
- }
- else
- {
- pyCmp = Runtime.PyFalse;
- }
- }
- return new NewReference(pyCmp);
+ return new NewReference(GetComparisonResult(op, cmp));
}
catch (ArgumentException e)
{
@@ -202,7 +167,53 @@ public static NewReference tp_richcompare(BorrowedReference ob, BorrowedReferenc
}
}
- private static bool TryGetSecondCompareOperandInstance(BorrowedReference left, BorrowedReference right, out CLRObject co1, out object co2Inst)
+ ///
+ /// Get the result of a comparison operation based on the operator and the comparison result.
+ ///
+ ///
+ /// This method is used to determine the result of a comparison operation, excluding equality and inequality.
+ ///
+ protected static BorrowedReference GetComparisonResult(int op, int comparisonResult)
+ {
+ BorrowedReference pyCmp;
+ if (comparisonResult < 0)
+ {
+ if (op == Runtime.Py_LT || op == Runtime.Py_LE)
+ {
+ pyCmp = Runtime.PyTrue;
+ }
+ else
+ {
+ pyCmp = Runtime.PyFalse;
+ }
+ }
+ else if (comparisonResult == 0)
+ {
+ if (op == Runtime.Py_LE || op == Runtime.Py_GE)
+ {
+ pyCmp = Runtime.PyTrue;
+ }
+ else
+ {
+ pyCmp = Runtime.PyFalse;
+ }
+ }
+ else
+ {
+ if (op == Runtime.Py_GE || op == Runtime.Py_GT)
+ {
+ pyCmp = Runtime.PyTrue;
+ }
+ else
+ {
+ pyCmp = Runtime.PyFalse;
+ }
+ }
+
+ return pyCmp;
+ }
+
+ protected static bool TryGetSecondCompareOperandInstance(BorrowedReference left, BorrowedReference right, out CLRObject co1, out object co2Inst)
{
co2Inst = null;
diff --git a/src/runtime/Types/DelegateObject.cs b/src/runtime/Types/DelegateObject.cs
index 43a75aba7..a469e6a52 100644
--- a/src/runtime/Types/DelegateObject.cs
+++ b/src/runtime/Types/DelegateObject.cs
@@ -103,7 +103,7 @@ public static NewReference tp_call(BorrowedReference ob, BorrowedReference args,
///
/// Implements __cmp__ for reflected delegate types.
///
- public new static NewReference tp_richcompare(BorrowedReference ob, BorrowedReference other, int op)
+ public static NewReference tp_richcompare(BorrowedReference ob, BorrowedReference other, int op)
{
if (op != Runtime.Py_EQ && op != Runtime.Py_NE)
{
diff --git a/src/runtime/Types/EnumObject.cs b/src/runtime/Types/EnumObject.cs
new file mode 100644
index 000000000..8c146ff50
--- /dev/null
+++ b/src/runtime/Types/EnumObject.cs
@@ -0,0 +1,218 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace Python.Runtime
+{
+ ///
+ /// Managed class that provides the implementation for reflected enum types.
+ ///
+ [Serializable]
+ internal class EnumObject : ClassBase
+ {
+ internal EnumObject(Type type) : base(type)
+ {
+ }
+
+ ///
+ /// Standard comparison implementation for instances of enum types.
+ ///
+ public static NewReference tp_richcompare(BorrowedReference ob, BorrowedReference other, int op)
+ {
+ object rightInstance;
+ CLRObject leftClrObject;
+ int comparisonResult;
+
+ switch (op)
+ {
+ case Runtime.Py_EQ:
+ case Runtime.Py_NE:
+ var pytrue = Runtime.PyTrue;
+ var pyfalse = Runtime.PyFalse;
+
+ // swap true and false for NE
+ if (op != Runtime.Py_EQ)
+ {
+ pytrue = Runtime.PyFalse;
+ pyfalse = Runtime.PyTrue;
+ }
+
+ if (ob == other)
+ {
+ return new NewReference(pytrue);
+ }
+
+ if (!TryGetSecondCompareOperandInstance(ob, other, out leftClrObject, out rightInstance))
+ {
+ return new NewReference(pyfalse);
+ }
+
+ if (rightInstance != null &&
+ TryCompare(leftClrObject.inst as Enum, rightInstance, out comparisonResult) &&
+ comparisonResult == 0)
+ {
+ return new NewReference(pytrue);
+ }
+ else
+ {
+ return new NewReference(pyfalse);
+ }
+
+ case Runtime.Py_LT:
+ case Runtime.Py_LE:
+ case Runtime.Py_GT:
+ case Runtime.Py_GE:
+ if (!TryGetSecondCompareOperandInstance(ob, other, out leftClrObject, out rightInstance))
+ {
+ return Exceptions.RaiseTypeError("Cannot get managed object");
+ }
+
+ if (rightInstance == null)
+ {
+ return Exceptions.RaiseTypeError($"Cannot compare {leftClrObject.inst.GetType()} to None");
+ }
+
+ try
+ {
+ if (!TryCompare(leftClrObject.inst as Enum, rightInstance, out comparisonResult))
+ {
+ return Exceptions.RaiseTypeError($"Cannot compare {leftClrObject.inst.GetType()} with {rightInstance.GetType()}");
+ }
+
+ return new NewReference(GetComparisonResult(op, comparisonResult));
+ }
+ catch (ArgumentException e)
+ {
+ return Exceptions.RaiseTypeError(e.Message);
+ }
+
+ default:
+ return new NewReference(Runtime.PyNotImplemented);
+ }
+ }
+
+ ///
+ /// Tries comparing the give enum to the right operand by converting it to the appropriate type if possible
+ ///
+ /// True if the right operand was converted to a supported type and the comparison was performed successfully
+ private static bool TryCompare(Enum left, object right, out int result)
+ {
+ result = int.MinValue;
+ var conversionSuccessful = true;
+ var leftType = left.GetType();
+ var rightType = right.GetType();
+
+ // Same enum comparison:
+ if (leftType == rightType)
+ {
+ result = left.CompareTo(right);
+ }
+ // Comparison with other enum types
+ else if (rightType.IsEnum)
+ {
+ var leftIsUnsigned = leftType.GetEnumUnderlyingType() == typeof(UInt64);
+ result = Compare(left, right as Enum, leftIsUnsigned);
+ }
+ else if (right is string rightString)
+ {
+ result = left.ToString().CompareTo(rightString);
+ }
+ else
+ {
+ var leftIsUnsigned = leftType.GetEnumUnderlyingType() == typeof(UInt64);
+ switch (right)
+ {
+ case double rightDouble:
+ result = Compare(left, rightDouble, leftIsUnsigned);
+ break;
+ case long rightLong:
+ result = Compare(left, rightLong, leftIsUnsigned);
+ break;
+ case ulong rightULong:
+ result = Compare(left, rightULong, leftIsUnsigned);
+ break;
+ case int rightInt:
+ result = Compare(left, (long)rightInt, leftIsUnsigned);
+ break;
+ case uint rightUInt:
+ result = Compare(left, (ulong)rightUInt, leftIsUnsigned);
+ break;
+ default:
+ conversionSuccessful = false;
+ break;
+ }
+ }
+
+ return conversionSuccessful;
+ }
+
+ #region Comparison against integers
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static int Compare(long a, ulong b)
+ {
+ if (a < 0) return -1;
+ return ((ulong)a).CompareTo(b);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static int Compare(Enum a, long b, bool isUnsigned)
+ {
+
+ if (isUnsigned)
+ {
+ return -Compare(b, Convert.ToUInt64(a));
+ }
+ return Convert.ToInt64(a).CompareTo(b);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static int Compare(Enum a, ulong b, bool inUnsigned)
+ {
+ if (inUnsigned)
+ {
+ return Convert.ToUInt64(a).CompareTo(b);
+ }
+ return Compare(Convert.ToInt64(a), b);
+ }
+
+ #endregion
+
+ #region Comparison against doubles
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static int Compare(Enum a, double b, bool isUnsigned)
+ {
+ if (isUnsigned)
+ {
+ var uIntA = Convert.ToUInt64(a);
+ if (uIntA < b) return -1;
+ if (uIntA > b) return 1;
+ return 0;
+ }
+
+ var intA = Convert.ToInt64(a);
+ if (intA < b) return -1;
+ if (intA > b) return 1;
+ return 0;
+ }
+
+ #endregion
+
+ #region Comparison against other enum types
+
+ ///
+ /// We support comparing enums of different types by comparing their underlying values.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static int Compare(Enum a, Enum b, bool isUnsigned)
+ {
+ if (b.GetType().GetEnumUnderlyingType() == typeof(UInt64))
+ {
+ return Compare(a, Convert.ToUInt64(b), isUnsigned);
+ }
+ return Compare(a, Convert.ToInt64(b), isUnsigned);
+ }
+
+ #endregion
+ }
+}
diff --git a/src/runtime/Util/OpsHelper.cs b/src/runtime/Util/OpsHelper.cs
index 89ce79e20..135a67163 100644
--- a/src/runtime/Util/OpsHelper.cs
+++ b/src/runtime/Util/OpsHelper.cs
@@ -156,428 +156,5 @@ public static double op_Division(double a, T b)
}
#endregion
-
- #region Int comparison operators
-
- public static bool op_Equality(T a, long b)
- {
- if (IsUnsigned)
- {
- var uvalue = Convert.ToUInt64(a);
- return b >= 0 && ((ulong)b) == uvalue;
- }
- return Convert.ToInt64(a) == b;
- }
-
- public static bool op_Equality(T a, ulong b)
- {
- if (IsUnsigned)
- {
- var uvalue = Convert.ToUInt64(a);
- return b == uvalue;
- }
- var ivalue = Convert.ToInt64(a);
- return ivalue >= 0 && ((ulong)ivalue) == b;
- }
-
- public static bool op_Equality(long a, T b)
- {
- return op_Equality(b, a);
- }
-
- public static bool op_Equality(ulong a, T b)
- {
- return op_Equality(b, a);
- }
-
- public static bool op_Inequality(T a, long b)
- {
- return !op_Equality(a, b);
- }
-
- public static bool op_Inequality(T a, ulong b)
- {
- return !op_Equality(a, b);
- }
-
- public static bool op_Inequality(long a, T b)
- {
- return !op_Equality(b, a);
- }
-
- public static bool op_Inequality(ulong a, T b)
- {
- return !op_Equality(b, a);
- }
-
- public static bool op_LessThan(T a, long b)
- {
- if (IsUnsigned)
- {
- var uvalue = Convert.ToUInt64(a);
- return b >= 0 && ((ulong)b) > uvalue;
- }
- return Convert.ToInt64(a) < b;
- }
-
- public static bool op_LessThan(T a, ulong b)
- {
- if (IsUnsigned)
- {
- var uvalue = Convert.ToUInt64(a);
- return b > uvalue;
- }
- var ivalue = Convert.ToInt64(a);
- return ivalue >= 0 && ((ulong)ivalue) < b;
- }
-
- public static bool op_LessThan(long a, T b)
- {
- return op_GreaterThan(b, a);
- }
-
- public static bool op_LessThan(ulong a, T b)
- {
- return op_GreaterThan(b, a);
- }
-
- public static bool op_GreaterThan(T a, long b)
- {
- if (IsUnsigned)
- {
- var uvalue = Convert.ToUInt64(a);
- return b >= 0 && ((ulong)b) < uvalue;
- }
- return Convert.ToInt64(a) > b;
- }
-
- public static bool op_GreaterThan(T a, ulong b)
- {
- if (IsUnsigned)
- {
- var uvalue = Convert.ToUInt64(a);
- return b < uvalue;
- }
- var ivalue = Convert.ToInt64(a);
- return ivalue >= 0 && ((ulong)ivalue) > b;
- }
-
- public static bool op_GreaterThan(long a, T b)
- {
- return op_LessThan(b, a);
- }
-
- public static bool op_GreaterThan(ulong a, T b)
- {
- return op_LessThan(b, a);
- }
-
- public static bool op_LessThanOrEqual(T a, long b)
- {
- if (IsUnsigned)
- {
- var uvalue = Convert.ToUInt64(a);
- return b >= 0 && ((ulong)b) >= uvalue;
- }
- return Convert.ToInt64(a) <= b;
- }
-
- public static bool op_LessThanOrEqual(T a, ulong b)
- {
- if (IsUnsigned)
- {
- var uvalue = Convert.ToUInt64(a);
- return b >= uvalue;
- }
- var ivalue = Convert.ToInt64(a);
- return ivalue >= 0 && ((ulong)ivalue) <= b;
- }
-
- public static bool op_LessThanOrEqual(long a, T b)
- {
- return op_GreaterThanOrEqual(b, a);
- }
-
- public static bool op_LessThanOrEqual(ulong a, T b)
- {
- return op_GreaterThanOrEqual(b, a);
- }
-
- public static bool op_GreaterThanOrEqual(T a, long b)
- {
- if (IsUnsigned)
- {
- var uvalue = Convert.ToUInt64(a);
- return b >= 0 && ((ulong)b) <= uvalue;
- }
- return Convert.ToInt64(a) >= b;
- }
-
- public static bool op_GreaterThanOrEqual(T a, ulong b)
- {
- if (IsUnsigned)
- {
- var uvalue = Convert.ToUInt64(a);
- return b <= uvalue;
- }
- var ivalue = Convert.ToInt64(a);
- return ivalue >= 0 && ((ulong)ivalue) >= b;
- }
-
- public static bool op_GreaterThanOrEqual(long a, T b)
- {
- return op_LessThanOrEqual(b, a);
- }
-
- public static bool op_GreaterThanOrEqual(ulong a, T b)
- {
- return op_LessThanOrEqual(b, a);
- }
-
- #endregion
-
- #region Double comparison operators
-
- public static bool op_Equality(T a, double b)
- {
- if (IsUnsigned)
- {
- return Convert.ToUInt64(a) == b;
- }
- return Convert.ToInt64(a) == b;
- }
-
- public static bool op_Equality(double a, T b)
- {
- return op_Equality(b, a);
- }
-
- public static bool op_Inequality(T a, double b)
- {
- return !op_Equality(a, b);
- }
-
- public static bool op_Inequality(double a, T b)
- {
- return !op_Equality(b, a);
- }
-
- public static bool op_LessThan(T a, double b)
- {
- if (IsUnsigned)
- {
- return Convert.ToUInt64(a) < b;
- }
- return Convert.ToInt64(a) < b;
- }
-
- public static bool op_LessThan(double a, T b)
- {
- return op_GreaterThan(b, a);
- }
-
- public static bool op_GreaterThan(T a, double b)
- {
- if (IsUnsigned)
- {
- return Convert.ToUInt64(a) > b;
- }
- return Convert.ToInt64(a) > b;
- }
-
- public static bool op_GreaterThan(double a, T b)
- {
- return op_LessThan(b, a);
- }
-
- public static bool op_LessThanOrEqual(T a, double b)
- {
- if (IsUnsigned)
- {
- return Convert.ToUInt64(a) <= b;
- }
- return Convert.ToInt64(a) <= b;
- }
-
- public static bool op_LessThanOrEqual(double a, T b)
- {
- return op_GreaterThanOrEqual(b, a);
- }
-
- public static bool op_GreaterThanOrEqual(T a, double b)
- {
- if (IsUnsigned)
- {
- return Convert.ToUInt64(a) >= b;
- }
- return Convert.ToInt64(a) >= b;
- }
-
- public static bool op_GreaterThanOrEqual(double a, T b)
- {
- return op_LessThanOrEqual(b, a);
- }
-
- #endregion
-
- #region String comparison operators
- public static bool op_Equality(T a, string b)
- {
- return a.ToString().Equals(b, StringComparison.InvariantCultureIgnoreCase);
- }
- public static bool op_Equality(string a, T b)
- {
- return op_Equality(b, a);
- }
-
- public static bool op_Inequality(T a, string b)
- {
- return !op_Equality(a, b);
- }
-
- public static bool op_Inequality(string a, T b)
- {
- return !op_Equality(b, a);
- }
-
- #endregion
-
- #region Enum comparison operators
-
- public static bool op_Equality(T a, Enum b)
- {
- if (b == null)
- {
- return false;
- }
-
- if (b.GetType().GetEnumUnderlyingType() == typeof(UInt64))
- {
- return op_Equality(a, Convert.ToUInt64(b));
- }
- return op_Equality(a, Convert.ToInt64(b));
- }
-
- public static bool op_Equality(Enum a, T b)
- {
- return op_Equality(b, a);
- }
-
- public static bool op_Inequality(T a, Enum b)
- {
- return !op_Equality(a, b);
- }
-
- public static bool op_Inequality(Enum a, T b)
- {
- return !op_Equality(b, a);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void ThrowOnNull(object obj, string @operator)
- {
- if (obj == null)
- {
- using (Py.GIL())
- {
- Exceptions.RaiseTypeError($"'{@operator}' not supported between instances of '{typeof(T).Name}' and null/None");
- PythonException.ThrowLastAsClrException();
- }
- }
- }
-
- public static bool op_LessThan(T a, Enum b)
- {
- ThrowOnNull(b, "<");
-
- if (b.GetType().GetEnumUnderlyingType() == typeof(UInt64))
- {
- return op_LessThan(a, Convert.ToUInt64(b));
- }
- return op_LessThan(a, Convert.ToInt64(b));
- }
-
- public static bool op_LessThan(Enum a, T b)
- {
- ThrowOnNull(a, "<");
- return op_GreaterThan(b, a);
- }
-
- public static bool op_GreaterThan(T a, Enum b)
- {
- ThrowOnNull(b, ">");
-
- if (b.GetType().GetEnumUnderlyingType() == typeof(UInt64))
- {
- return op_GreaterThan(a, Convert.ToUInt64(b));
- }
- return op_GreaterThan(a, Convert.ToInt64(b));
- }
-
- public static bool op_GreaterThan(Enum a, T b)
- {
- ThrowOnNull(a, ">");
- return op_LessThan(b, a);
- }
-
- public static bool op_LessThanOrEqual(T a, Enum b)
- {
- ThrowOnNull(b, "<=");
-
- if (b.GetType().GetEnumUnderlyingType() == typeof(UInt64))
- {
- return op_LessThanOrEqual(a, Convert.ToUInt64(b));
- }
- return op_LessThanOrEqual(a, Convert.ToInt64(b));
- }
-
- public static bool op_LessThanOrEqual(Enum a, T b)
- {
- ThrowOnNull(a, "<=");
- return op_GreaterThanOrEqual(b, a);
- }
-
- public static bool op_GreaterThanOrEqual(T a, Enum b)
- {
- ThrowOnNull(b, ">=");
-
- if (b.GetType().GetEnumUnderlyingType() == typeof(UInt64))
- {
- return op_GreaterThanOrEqual(a, Convert.ToUInt64(b));
- }
- return op_GreaterThanOrEqual(a, Convert.ToInt64(b));
- }
-
- public static bool op_GreaterThanOrEqual(Enum a, T b)
- {
- ThrowOnNull(a, ">=");
- return op_LessThanOrEqual(b, a);
- }
-
- #endregion
-
- #region Object equality operators
-
- public static bool op_Equality(T a, object b)
- {
- return false;
- }
-
- public static bool op_Equality(object a, T b)
- {
- return false;
- }
-
- public static bool op_Inequality(T a, object b)
- {
- return true;
- }
-
- public static bool op_Inequality(object a, T b)
- {
- return true;
- }
-
- #endregion
}
}