From 8ff17498661c8ceffcd3bc1ba8d0975633d866af Mon Sep 17 00:00:00 2001 From: Martin Molinero Date: Wed, 17 Apr 2024 11:34:54 -0300 Subject: [PATCH] Push fake snakenamed methods at the end --- src/embed_tests/ClassManagerTests.cs | 28 ++ src/embed_tests/TestMethodBinder.cs | 422 ++++++++++++++++----------- src/runtime/ClassManager.cs | 9 +- src/runtime/MethodBinder.cs | 4 +- 4 files changed, 283 insertions(+), 180 deletions(-) diff --git a/src/embed_tests/ClassManagerTests.cs b/src/embed_tests/ClassManagerTests.cs index 340700333..1cc673f81 100644 --- a/src/embed_tests/ClassManagerTests.cs +++ b/src/embed_tests/ClassManagerTests.cs @@ -710,6 +710,11 @@ public int another_int_property() return 654; } + public dynamic a(AlreadyDefinedSnakeCaseMemberTestBaseClass a) + { + throw new Exception("a(AlreadyDefinedSnakeCaseMemberTestBaseClass)"); + } + public int a() { throw new Exception("a()"); @@ -766,6 +771,10 @@ public int A() { throw new Exception("A()"); } + public PyObject A(PyObject a) + { + throw new Exception("A(PyObject)"); + } public override int get_value(int x) { throw new Exception("override get_value(int x)"); @@ -801,8 +810,27 @@ public override int GetValue2(int x) // original beats fake [TestCase(typeof(AlreadyDefinedSnakeCaseMemberTestDerivedClass), "get_value_2", new object[] { 2 }, "get_value_2(int x)")] [TestCase(typeof(AlreadyDefinedSnakeCaseMemberTestDerivedClass), "get_value_3", new object[] { 2 }, "get_value_3(int x)")] + + [TestCase(typeof(AlreadyDefinedSnakeCaseMemberTestDerivedClass), "a", new object[] { "AlreadyDefinedSnakeCaseMemberTestBaseClass" }, "a(AlreadyDefinedSnakeCaseMemberTestBaseClass)")] + // A(PyObject) is real + [TestCase(typeof(AlreadyDefinedSnakeCaseMemberTestDerivedClass), "A", new object[] { "AlreadyDefinedSnakeCaseMemberTestBaseClass" }, "A(PyObject)")] + [TestCase(typeof(AlreadyDefinedSnakeCaseMemberTestDerivedClass), "a", new object[] { "Type" }, "A(PyObject)")] + [TestCase(typeof(AlreadyDefinedSnakeCaseMemberTestDerivedClass), "A", new object[] { "Type" }, "A(PyObject)")] + [TestCase(typeof(AlreadyDefinedSnakeCaseMemberTestDerivedClass), "A", new object[] { "Type" }, "A(PyObject)")] public void BindsSnakeCasedMethodAsOverload(Type type, string methodName, object[] args, string expectedMessage) { + if (args.Length == 1) + { + if (args[0] is "AlreadyDefinedSnakeCaseMemberTestBaseClass") + { + args = new object[] { new AlreadyDefinedSnakeCaseMemberTestBaseClass() }; + } + else if (args[0] is "Type") + { + args = new object[] { typeof(string) }; + } + } + var obj = Activator.CreateInstance(type); using var pyObj = obj.ToPython(); diff --git a/src/embed_tests/TestMethodBinder.cs b/src/embed_tests/TestMethodBinder.cs index 757b596e6..f3a65b477 100644 --- a/src/embed_tests/TestMethodBinder.cs +++ b/src/embed_tests/TestMethodBinder.cs @@ -4,7 +4,7 @@ using NUnit.Framework; using System.Collections.Generic; using System.Diagnostics; -using System.Threading; +using static Python.Runtime.Py; namespace Python.EmbeddingTest { @@ -44,8 +44,6 @@ def NumericalArgumentMethodInteger(self): self.NumericalArgumentMethod(1) def NumericalArgumentMethodDouble(self): self.NumericalArgumentMethod(0.1) - def NumericalArgumentMethodNumpyFloat(self): - self.NumericalArgumentMethod(TestMethodBinder.Numpy.float(0.1)) def NumericalArgumentMethodNumpy64Float(self): self.NumericalArgumentMethod(TestMethodBinder.Numpy.float64(0.1)) def ListKeyValuePairTest(self): @@ -81,7 +79,11 @@ public void SetUp() catch (PythonException) { } - module = PyModule.FromString("module", testModule).GetAttr("PythonModel").Invoke(); + + using (Py.GIL()) + { + module = PyModule.FromString("module", testModule).GetAttr("PythonModel").Invoke(); + } } [OneTimeTearDown] @@ -93,50 +95,61 @@ public void Dispose() [Test] public void MethodCalledList() { - module.TestList(); + using (Py.GIL()) + module.TestList(); Assert.AreEqual("List(List collection)", CSharpModel.MethodCalled); } [Test] public void MethodCalledReadOnlyCollection() { - module.TestListReadOnlyCollection(); + using (Py.GIL()) + module.TestListReadOnlyCollection(); Assert.AreEqual("List(IReadOnlyCollection collection)", CSharpModel.MethodCalled); } [Test] public void MethodCalledEnumerable() { - module.TestEnumerable(); + using (Py.GIL()) + module.TestEnumerable(); Assert.AreEqual("List(IEnumerable collection)", CSharpModel.MethodCalled); } [Test] public void ListToEnumerableExpectingMethod() { - Assert.DoesNotThrow(() => module.TestF()); + using (Py.GIL()) + Assert.DoesNotThrow(() => module.TestF()); } [Test] public void ListToListExpectingMethod() { - Assert.DoesNotThrow(() => module.TestG()); + using (Py.GIL()) + Assert.DoesNotThrow(() => module.TestG()); } [Test] public void ImplicitConversionToString() { - var data = (string)module.TestA(); - // we assert implicit conversion took place - Assert.AreEqual("OnlyString impl: implicit to string", data); + using (Py.GIL()) + { + var data = (string)module.TestA(); + // we assert implicit conversion took place + Assert.AreEqual("OnlyString impl: implicit to string", data); + } } [Test] public void ImplicitConversionToClass() { - var data = (string)module.TestB(); - // we assert implicit conversion took place - Assert.AreEqual("OnlyClass impl", data); + using (Py.GIL()) + { + var data = (string)module.TestB(); + // we assert implicit conversion took place + Assert.AreEqual("OnlyClass impl", data); + } } // Reproduces a bug in which program explodes when implicit conversion fails @@ -144,74 +157,86 @@ public void ImplicitConversionToClass() [Test] public void ImplicitConversionErrorHandling() { - var errorCaught = false; - try - { - var data = (string)module.TestH(); - } - catch (Exception e) + using (Py.GIL()) { - errorCaught = true; - Assert.AreEqual("Failed to implicitly convert Python.EmbeddingTest.TestMethodBinder+ErroredImplicitConversion to System.String", e.Message); - } + var errorCaught = false; + try + { + var data = (string)module.TestH(); + } + catch (Exception e) + { + errorCaught = true; + Assert.AreEqual("Failed to implicitly convert Python.EmbeddingTest.TestMethodBinder+ErroredImplicitConversion to System.String", e.Message); + } - Assert.IsTrue(errorCaught); + Assert.IsTrue(errorCaught); + } } [Test] public void WillAvoidUsingImplicitConversionIfPossible_String() { - var data = (string)module.TestC(); - // we assert no implicit conversion took place - Assert.AreEqual("string impl: input string", data); + using (Py.GIL()) + { + var data = (string)module.TestC(); + // we assert no implicit conversion took place + Assert.AreEqual("string impl: input string", data); + } } [Test] public void WillAvoidUsingImplicitConversionIfPossible_Class() { - var data = (string)module.TestD(); - // we assert no implicit conversion took place - Assert.AreEqual("TestImplicitConversion impl", data); + using (Py.GIL()) + { + var data = (string)module.TestD(); + // we assert no implicit conversion took place + Assert.AreEqual("TestImplicitConversion impl", data); + } } [Test] public void ArrayLength() { - var array = new[] { "pepe", "pinocho" }; - var data = (bool)module.TestE(array); + using (Py.GIL()) + { + var array = new[] { "pepe", "pinocho" }; + var data = (bool)module.TestE(array); - // Assert it is true - Assert.AreEqual(true, data); + // Assert it is true + Assert.AreEqual(true, data); + } } [Test] public void MethodDateTimeAndTimeSpan() { - Assert.DoesNotThrow(() => module.MethodTimeSpanTest()); + using (Py.GIL()) + Assert.DoesNotThrow(() => module.MethodTimeSpanTest()); } [Test] public void NumericalArgumentMethod() { - CSharpModel.ProvidedArgument = 0; - - module.NumericalArgumentMethodInteger(); - Assert.AreEqual(typeof(int), CSharpModel.ProvidedArgument.GetType()); - Assert.AreEqual(1, CSharpModel.ProvidedArgument); + using (Py.GIL()) + { + CSharpModel.ProvidedArgument = 0; - // python float type has double precision - module.NumericalArgumentMethodDouble(); - Assert.AreEqual(typeof(double), CSharpModel.ProvidedArgument.GetType()); - Assert.AreEqual(0.1d, CSharpModel.ProvidedArgument); + module.NumericalArgumentMethodInteger(); + Assert.AreEqual(typeof(int), CSharpModel.ProvidedArgument.GetType()); + Assert.AreEqual(1, CSharpModel.ProvidedArgument); - module.NumericalArgumentMethodNumpyFloat(); - Assert.AreEqual(typeof(double), CSharpModel.ProvidedArgument.GetType()); - Assert.AreEqual(0.1d, CSharpModel.ProvidedArgument); + // python float type has double precision + module.NumericalArgumentMethodDouble(); + Assert.AreEqual(typeof(double), CSharpModel.ProvidedArgument.GetType()); + Assert.AreEqual(0.1d, CSharpModel.ProvidedArgument); - module.NumericalArgumentMethodNumpy64Float(); - Assert.AreEqual(typeof(decimal), CSharpModel.ProvidedArgument.GetType()); - Assert.AreEqual(0.1, CSharpModel.ProvidedArgument); + module.NumericalArgumentMethodNumpy64Float(); + Assert.AreEqual(typeof(decimal), CSharpModel.ProvidedArgument.GetType()); + Assert.AreEqual(0.1, CSharpModel.ProvidedArgument); + } } [Test] @@ -219,100 +244,117 @@ public void NumericalArgumentMethod() // so moving example test here so we import numpy once public void TestReadme() { - Assert.AreEqual("1.0", Numpy.cos(Numpy.pi * 2).ToString()); + using (Py.GIL()) + { + Assert.AreEqual("1.0", Numpy.cos(Numpy.pi * 2).ToString()); - dynamic sin = Numpy.sin; - StringAssert.StartsWith("-0.95892", sin(5).ToString()); + dynamic sin = Numpy.sin; + StringAssert.StartsWith("-0.95892", sin(5).ToString()); - double c = Numpy.cos(5) + sin(5); - Assert.AreEqual(-0.675262, c, 0.01); + double c = Numpy.cos(5) + sin(5); + Assert.AreEqual(-0.675262, c, 0.01); - dynamic a = Numpy.array(new List { 1, 2, 3 }); - Assert.AreEqual("float64", a.dtype.ToString()); + dynamic a = Numpy.array(new List { 1, 2, 3 }); + Assert.AreEqual("float64", a.dtype.ToString()); - dynamic b = Numpy.array(new List { 6, 5, 4 }, Py.kw("dtype", Numpy.int32)); - Assert.AreEqual("int32", b.dtype.ToString()); + dynamic b = Numpy.array(new List { 6, 5, 4 }, Py.kw("dtype", Numpy.int32)); + Assert.AreEqual("int32", b.dtype.ToString()); - Assert.AreEqual("[ 6. 10. 12.]", (a * b).ToString().Replace(" ", " ")); + Assert.AreEqual("[ 6. 10. 12.]", (a * b).ToString().Replace(" ", " ")); + } } [Test] public void NumpyDateTime64() { - var number = 10; - var numpyDateTime = Numpy.datetime64("2011-02"); + using (Py.GIL()) + { + var number = 10; + var numpyDateTime = Numpy.datetime64("2011-02"); - object result; - var converted = Converter.ToManaged(numpyDateTime, typeof(DateTime), out result, false); + object result; + var converted = Converter.ToManaged(numpyDateTime, typeof(DateTime), out result, false); - Assert.IsTrue(converted); - Assert.AreEqual(new DateTime(2011, 02, 1), result); + Assert.IsTrue(converted); + Assert.AreEqual(new DateTime(2011, 02, 1), result); + } } [Test] public void ListKeyValuePair() { - Assert.DoesNotThrow(() => module.ListKeyValuePairTest()); + using (Py.GIL()) + Assert.DoesNotThrow(() => module.ListKeyValuePairTest()); } [Test] public void EnumerableKeyValuePair() { - Assert.DoesNotThrow(() => module.EnumerableKeyValuePairTest()); + using (Py.GIL()) + Assert.DoesNotThrow(() => module.EnumerableKeyValuePairTest()); } [Test] public void MethodWithParamsPerformance() { - var stopwatch = new Stopwatch(); - stopwatch.Start(); - for (var i = 0; i < 100000; i++) + using (Py.GIL()) { - module.MethodWithParamsTest(); - } - stopwatch.Stop(); + var stopwatch = new Stopwatch(); + stopwatch.Start(); + for (var i = 0; i < 100000; i++) + { + module.MethodWithParamsTest(); + } + stopwatch.Stop(); - Console.WriteLine($"Took: {stopwatch.ElapsedMilliseconds}"); + Console.WriteLine($"Took: {stopwatch.ElapsedMilliseconds}"); + } } [Test] public void NumericalArgumentMethodNumpy64FloatPerformance() { - var stopwatch = new Stopwatch(); - stopwatch.Start(); - for (var i = 0; i < 100000; i++) + using (Py.GIL()) { - module.NumericalArgumentMethodNumpy64Float(); - } - stopwatch.Stop(); + var stopwatch = new Stopwatch(); + stopwatch.Start(); + for (var i = 0; i < 100000; i++) + { + module.NumericalArgumentMethodNumpy64Float(); + } + stopwatch.Stop(); - Console.WriteLine($"Took: {stopwatch.ElapsedMilliseconds}"); + Console.WriteLine($"Took: {stopwatch.ElapsedMilliseconds}"); + } } [Test] public void MethodWithParamsTest() { - Assert.DoesNotThrow(() => module.MethodWithParamsTest()); + using (Py.GIL()) + Assert.DoesNotThrow(() => module.MethodWithParamsTest()); } [Test] public void TestNonStaticGenericMethodBinding() { - // Test matching generic on instance functions - // i.e. function signature is (Generic var1) + using (Py.GIL()) + { + // Test matching generic on instance functions + // i.e. function signature is (Generic var1) - // Run in C# - var class1 = new TestGenericClass1(); - var class2 = new TestGenericClass2(); + // Run in C# + var class1 = new TestGenericClass1(); + var class2 = new TestGenericClass2(); - class1.TestNonStaticGenericMethod(class1); - class2.TestNonStaticGenericMethod(class2); + class1.TestNonStaticGenericMethod(class1); + class2.TestNonStaticGenericMethod(class2); - Assert.AreEqual(1, class1.Value); - Assert.AreEqual(1, class2.Value); + Assert.AreEqual(1, class1.Value); + Assert.AreEqual(1, class2.Value); - // Run in Python - Assert.DoesNotThrow(() => PyModule.FromString("test", @" + // Run in Python + Assert.DoesNotThrow(() => PyModule.FromString("test", @" from clr import AddReference AddReference(""System"") AddReference(""Python.EmbeddingTest"") @@ -325,27 +367,30 @@ from Python.EmbeddingTest import * if class1.Value != 1 or class2.Value != 1: raise AssertionError('Values were not updated') -")); + ")); + } } [Test] public void TestGenericMethodBinding() { - // Test matching generic - // i.e. function signature is (Generic var1) + using (Py.GIL()) + { + // Test matching generic + // i.e. function signature is (Generic var1) - // Run in C# - var class1 = new TestGenericClass1(); - var class2 = new TestGenericClass2(); + // Run in C# + var class1 = new TestGenericClass1(); + var class2 = new TestGenericClass2(); - TestGenericMethod(class1); - TestGenericMethod(class2); + TestGenericMethod(class1); + TestGenericMethod(class2); - Assert.AreEqual(1, class1.Value); - Assert.AreEqual(1, class2.Value); + Assert.AreEqual(1, class1.Value); + Assert.AreEqual(1, class2.Value); - // Run in Python - Assert.DoesNotThrow(() => PyModule.FromString("test", @" + // Run in Python + Assert.DoesNotThrow(() => PyModule.FromString("test", @" from clr import AddReference AddReference(""System"") AddReference(""Python.EmbeddingTest"") @@ -359,26 +404,29 @@ from Python.EmbeddingTest import * if class1.Value != 1 or class2.Value != 1: raise AssertionError('Values were not updated') ")); + } } [Test] public void TestMultipleGenericMethodBinding() { - // Test matching multiple generics - // i.e. function signature is (Generic var1) + using (Py.GIL()) + { + // Test matching multiple generics + // i.e. function signature is (Generic var1) - // Run in C# - var class1 = new TestMultipleGenericClass1(); - var class2 = new TestMultipleGenericClass2(); + // Run in C# + var class1 = new TestMultipleGenericClass1(); + var class2 = new TestMultipleGenericClass2(); - TestMultipleGenericMethod(class1); - TestMultipleGenericMethod(class2); + TestMultipleGenericMethod(class1); + TestMultipleGenericMethod(class2); - Assert.AreEqual(1, class1.Value); - Assert.AreEqual(1, class2.Value); + Assert.AreEqual(1, class1.Value); + Assert.AreEqual(1, class2.Value); - // Run in Python - Assert.DoesNotThrow(() => PyModule.FromString("test", @" + // Run in Python + Assert.DoesNotThrow(() => PyModule.FromString("test", @" from clr import AddReference AddReference(""System"") AddReference(""Python.EmbeddingTest"") @@ -392,34 +440,37 @@ from Python.EmbeddingTest import * if class1.Value != 1 or class2.Value != 1: raise AssertionError('Values were not updated') ")); + } } [Test] public void TestMultipleGenericParamMethodBinding() { - // Test multiple param generics matching - // i.e. function signature is (Generic1 var1, Generic var2) + using (Py.GIL()) + { + // Test multiple param generics matching + // i.e. function signature is (Generic1 var1, Generic var2) - // Run in C# - var class1a = new TestGenericClass1(); - var class1b = new TestMultipleGenericClass1(); + // Run in C# + var class1a = new TestGenericClass1(); + var class1b = new TestMultipleGenericClass1(); - TestMultipleGenericParamsMethod(class1a, class1b); + TestMultipleGenericParamsMethod(class1a, class1b); - Assert.AreEqual(1, class1a.Value); - Assert.AreEqual(1, class1a.Value); + Assert.AreEqual(1, class1a.Value); + Assert.AreEqual(1, class1a.Value); - var class2a = new TestGenericClass2(); - var class2b = new TestMultipleGenericClass2(); + var class2a = new TestGenericClass2(); + var class2b = new TestMultipleGenericClass2(); - TestMultipleGenericParamsMethod(class2a, class2b); + TestMultipleGenericParamsMethod(class2a, class2b); - Assert.AreEqual(1, class2a.Value); - Assert.AreEqual(1, class2b.Value); + Assert.AreEqual(1, class2a.Value); + Assert.AreEqual(1, class2b.Value); - // Run in Python - Assert.DoesNotThrow(() => PyModule.FromString("test", @" + // Run in Python + Assert.DoesNotThrow(() => PyModule.FromString("test", @" from clr import AddReference AddReference(""System"") AddReference(""Python.EmbeddingTest"") @@ -440,33 +491,36 @@ raise AssertionError('Values were not updated') if class2a.Value != 1 or class2b.Value != 1: raise AssertionError('Values were not updated') ")); + } } [Test] public void TestMultipleGenericParamMethodBinding_MixedOrder() { - // Test matching multiple param generics with mixed order - // i.e. function signature is (Generic1 var1, Generic var2) + using (Py.GIL()) + { + // Test matching multiple param generics with mixed order + // i.e. function signature is (Generic1 var1, Generic var2) - // Run in C# - var class1a = new TestGenericClass2(); - var class1b = new TestMultipleGenericClass1(); + // Run in C# + var class1a = new TestGenericClass2(); + var class1b = new TestMultipleGenericClass1(); - TestMultipleGenericParamsMethod2(class1a, class1b); + TestMultipleGenericParamsMethod2(class1a, class1b); - Assert.AreEqual(1, class1a.Value); - Assert.AreEqual(1, class1a.Value); + Assert.AreEqual(1, class1a.Value); + Assert.AreEqual(1, class1a.Value); - var class2a = new TestGenericClass1(); - var class2b = new TestMultipleGenericClass2(); + var class2a = new TestGenericClass1(); + var class2b = new TestMultipleGenericClass2(); - TestMultipleGenericParamsMethod2(class2a, class2b); + TestMultipleGenericParamsMethod2(class2a, class2b); - Assert.AreEqual(1, class2a.Value); - Assert.AreEqual(1, class2b.Value); + Assert.AreEqual(1, class2a.Value); + Assert.AreEqual(1, class2b.Value); - // Run in Python - Assert.DoesNotThrow(() => PyModule.FromString("test", @" + // Run in Python + Assert.DoesNotThrow(() => PyModule.FromString("test", @" from clr import AddReference AddReference(""System"") AddReference(""Python.EmbeddingTest"") @@ -487,13 +541,15 @@ raise AssertionError('Values were not updated') if class2a.Value != 1 or class2b.Value != 1: raise AssertionError('Values were not updated') ")); + } } [Test] public void TestPyClassGenericBinding() { - // Overriding our generics in Python we should still match with the generic method - Assert.DoesNotThrow(() => PyModule.FromString("test", @" + using (Py.GIL()) + // Overriding our generics in Python we should still match with the generic method + Assert.DoesNotThrow(() => PyModule.FromString("test", @" from clr import AddReference AddReference(""System"") AddReference(""Python.EmbeddingTest"") @@ -520,14 +576,15 @@ raise AssertionError('Values were not updated') [Test] public void TestNonGenericIsUsedWhenAvailable() { - // Run in C# - var class1 = new TestGenericClass3(); - TestGenericMethod(class1); - Assert.AreEqual(10, class1.Value); + using (Py.GIL()) + {// Run in C# + var class1 = new TestGenericClass3(); + TestGenericMethod(class1); + Assert.AreEqual(10, class1.Value); - // When available, should select non-generic method over generic method - Assert.DoesNotThrow(() => PyModule.FromString("test", @" + // When available, should select non-generic method over generic method + Assert.DoesNotThrow(() => PyModule.FromString("test", @" from clr import AddReference AddReference(""System"") AddReference(""Python.EmbeddingTest"") @@ -540,18 +597,20 @@ from Python.EmbeddingTest import * if class1.Value != 10: raise AssertionError('Value was not updated') ")); + } } [Test] public void TestMatchTypedGenericOverload() { - // Test to ensure we can match a typed generic overload - // even when there are other matches that would apply. - var class1 = new TestGenericClass4(); - TestGenericMethod(class1); - Assert.AreEqual(15, class1.Value); + using (Py.GIL()) + {// Test to ensure we can match a typed generic overload + // even when there are other matches that would apply. + var class1 = new TestGenericClass4(); + TestGenericMethod(class1); + Assert.AreEqual(15, class1.Value); - Assert.DoesNotThrow(() => PyModule.FromString("test", @" + Assert.DoesNotThrow(() => PyModule.FromString("test", @" from clr import AddReference AddReference(""System"") AddReference(""Python.EmbeddingTest"") @@ -564,20 +623,24 @@ from Python.EmbeddingTest import * if class1.Value != 15: raise AssertionError('Value was not updated') ")); + } } [Test] public void TestGenericBindingSpeed() { - var stopwatch = new Stopwatch(); - stopwatch.Start(); - for (int i = 0; i < 10000; i++) + using (Py.GIL()) { - TestMultipleGenericParamMethodBinding(); - } - stopwatch.Stop(); + var stopwatch = new Stopwatch(); + stopwatch.Start(); + for (int i = 0; i < 10000; i++) + { + TestMultipleGenericParamMethodBinding(); + } + stopwatch.Stop(); - Console.WriteLine($"Took: {stopwatch.ElapsedMilliseconds} ms"); + Console.WriteLine($"Took: {stopwatch.ElapsedMilliseconds} ms"); + } } [Test] @@ -586,7 +649,8 @@ public void TestGenericTypeMatchingWithConvertedPyType() // This test ensures that we can still match and bind a generic method when we // have a converted pytype in the args (py timedelta -> C# TimeSpan) - Assert.DoesNotThrow(() => PyModule.FromString("test", @" + using (Py.GIL()) + Assert.DoesNotThrow(() => PyModule.FromString("test", @" from datetime import timedelta from clr import AddReference AddReference(""System"") @@ -608,7 +672,8 @@ public void TestGenericTypeMatchingWithDefaultArgs() { // This test ensures that we can still match and bind a generic method when we have default args - Assert.DoesNotThrow(() => PyModule.FromString("test", @" + using (Py.GIL()) + Assert.DoesNotThrow(() => PyModule.FromString("test", @" from datetime import timedelta from clr import AddReference AddReference(""System"") @@ -634,7 +699,8 @@ public void TestGenericTypeMatchingWithNullDefaultArgs() // This test ensures that we can still match and bind a generic method when we have \ // null default args, important because caching by arg types occurs - Assert.DoesNotThrow(() => PyModule.FromString("test", @" + using (Py.GIL()) + Assert.DoesNotThrow(() => PyModule.FromString("test", @" from datetime import timedelta from clr import AddReference AddReference(""System"") @@ -657,8 +723,9 @@ raise AssertionError('Value was not 50, was {class1.Value}') [Test] public void TestMatchPyDateToDateTime() { - // This test ensures that we match py datetime.date object to C# DateTime object - Assert.DoesNotThrow(() => PyModule.FromString("test", @" + using (Py.GIL()) + // This test ensures that we match py datetime.date object to C# DateTime object + Assert.DoesNotThrow(() => PyModule.FromString("test", @" from datetime import * from clr import AddReference AddReference(""System"") @@ -779,9 +846,12 @@ public void ListEnumerable(IEnumerable collection) private static void AssertErrorNotOccurred() { - if (Exceptions.ErrorOccurred()) + using (Py.GIL()) { - throw new Exception("Error occurred"); + if (Exceptions.ErrorOccurred()) + { + throw new Exception("Error occurred"); + } } } diff --git a/src/runtime/ClassManager.cs b/src/runtime/ClassManager.cs index a4b730984..e5d31f4f1 100644 --- a/src/runtime/ClassManager.cs +++ b/src/runtime/ClassManager.cs @@ -370,9 +370,10 @@ private static ClassInfo GetClassInfo(Type type, ClassBase impl) if (m.DeclaringType == type) { local.Add(m.Name); - if (m is MethodInfo) + var snakeName = m.Name.ToSnakeCase(); + if (snakeName != m.Name && m is MethodInfo) { - snakeCasedMethods.Add(m.Name.ToSnakeCase()); + snakeCasedMethods.Add(snakeName); } } } @@ -410,6 +411,10 @@ private static ClassInfo GetClassInfo(Type type, ClassBase impl) { // the method binding is done by the case sensitive name and it's handled by a single MethodBinder instance, so in derived classes // we need to add the methods of the base classes which have the same name or snake name + // - the name of this method (of a base type) matches a snakename method of this type + // - the snake name of this method (of a base type) matches: + // - a method name in this type + // - a snakename method of this type var snakeName = m.Name.ToSnakeCase(); if (snakeCasedMethods.Contains(m.Name) || local.Contains(snakeName) || snakeCasedMethods.Contains(snakeName)) diff --git a/src/runtime/MethodBinder.cs b/src/runtime/MethodBinder.cs index bbee830c7..e951724f2 100644 --- a/src/runtime/MethodBinder.cs +++ b/src/runtime/MethodBinder.cs @@ -338,11 +338,11 @@ private static int GetPrecedence(MethodInformation methodInformation) val += ArgPrecedence(info.ReturnType, methodInformation); if (mi.DeclaringType == mi.ReflectedType) { - val += methodInformation.IsOriginal ? 0 : 3000; + val += methodInformation.IsOriginal ? 0 : 300000; } else { - val += methodInformation.IsOriginal ? 2000 : 4000; + val += methodInformation.IsOriginal ? 2000 : 400000; } }