From 25a257c7bfa88673a4f1d5e0a4133a1341c9f53d Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Mon, 4 Feb 2019 20:28:16 -0800 Subject: [PATCH 1/5] generate more useful message, when a .NET overload can't be found, that matches Python parameter types --- src/embed_tests/TestCallbacks.cs | 30 ++++++++++++++++++++++++++++++ src/runtime/methodbinder.cs | 20 ++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 src/embed_tests/TestCallbacks.cs diff --git a/src/embed_tests/TestCallbacks.cs b/src/embed_tests/TestCallbacks.cs new file mode 100644 index 000000000..673be4fb1 --- /dev/null +++ b/src/embed_tests/TestCallbacks.cs @@ -0,0 +1,30 @@ +using System; + +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest { + public class TestCallbacks { + [OneTimeSetUp] + public void SetUp() { + string path = Environment.GetEnvironmentVariable("PATH"); + } + + [OneTimeTearDown] + public void Dispose() { + PythonEngine.Shutdown(); + } + + [Test] + public void TestNoOverloadException() { + int passed = 0; + var aFunctionThatCallsIntoPython = new Action(value => passed = value); + using (Py.GIL()) { + dynamic callWith42 = PythonEngine.Eval("lambda f: f([42])"); + var error = Assert.Throws(() => callWith42(aFunctionThatCallsIntoPython.ToPython())); + Assert.AreEqual("TypeError", error.PythonTypeName); + StringAssert.EndsWith("()", error.Message); + } + } + } +} diff --git a/src/runtime/methodbinder.cs b/src/runtime/methodbinder.cs index 7471d5d7c..5d608fb06 100644 --- a/src/runtime/methodbinder.cs +++ b/src/runtime/methodbinder.cs @@ -560,6 +560,26 @@ internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, MethodBase i { value += $" for {methodinfo[0].Name}"; } + + long argCount = Runtime.PyTuple_Size(args); + value += ": ("; + for(long argIndex = 0; argIndex < argCount; argIndex++) { + var arg = Runtime.PyTuple_GetItem(args, argIndex); + if (arg != IntPtr.Zero) { + var type = Runtime.PyObject_Type(arg); + if (type != IntPtr.Zero) { + var description = Runtime.PyObject_Unicode(type); + if (description != IntPtr.Zero) { + value += Runtime.GetManagedString(description); + Runtime.XDecref(description); + } + } + } + + if (argIndex + 1 < argCount) + value += ", "; + } + value += ")"; Exceptions.SetError(Exceptions.TypeError, value); return IntPtr.Zero; } From ba8cad2a82817201498f96316ee58f9f0c8c0455 Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Sun, 10 Feb 2019 22:40:59 -0800 Subject: [PATCH 2/5] provide detailed error message, when an overload can't be found when calling C# from Python Related: #811, #265, #782 --- src/runtime/methodbinder.cs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/runtime/methodbinder.cs b/src/runtime/methodbinder.cs index 5d608fb06..95b953555 100644 --- a/src/runtime/methodbinder.cs +++ b/src/runtime/methodbinder.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Reflection; +using System.Text; namespace Python.Runtime { @@ -555,32 +556,36 @@ internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, MethodBase i if (binding == null) { - var value = "No method matches given arguments"; + var value = new StringBuilder("No method matches given arguments"); if (methodinfo != null && methodinfo.Length > 0) { - value += $" for {methodinfo[0].Name}"; + value.Append($" for {methodinfo[0].Name}"); } long argCount = Runtime.PyTuple_Size(args); - value += ": ("; + value.Append(": ("); for(long argIndex = 0; argIndex < argCount; argIndex++) { var arg = Runtime.PyTuple_GetItem(args, argIndex); if (arg != IntPtr.Zero) { var type = Runtime.PyObject_Type(arg); if (type != IntPtr.Zero) { - var description = Runtime.PyObject_Unicode(type); - if (description != IntPtr.Zero) { - value += Runtime.GetManagedString(description); - Runtime.XDecref(description); + try { + var description = Runtime.PyObject_Unicode(type); + if (description != IntPtr.Zero) { + value.Append(Runtime.GetManagedString(description)); + Runtime.XDecref(description); + } + } finally { + Runtime.XDecref(type); } } } if (argIndex + 1 < argCount) - value += ", "; + value.Append(", "); } - value += ")"; - Exceptions.SetError(Exceptions.TypeError, value); + value.Append(')'); + Exceptions.SetError(Exceptions.TypeError, value.ToString()); return IntPtr.Zero; } From ce20ffb245a1f33464e631301f74b6e2dd377913 Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Wed, 26 Jun 2019 13:06:33 -0700 Subject: [PATCH 3/5] fixed broken OneTimeSetUp in TestCallbacks --- src/embed_tests/TestCallbacks.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embed_tests/TestCallbacks.cs b/src/embed_tests/TestCallbacks.cs index 673be4fb1..8cf698689 100644 --- a/src/embed_tests/TestCallbacks.cs +++ b/src/embed_tests/TestCallbacks.cs @@ -7,7 +7,7 @@ namespace Python.EmbeddingTest { public class TestCallbacks { [OneTimeSetUp] public void SetUp() { - string path = Environment.GetEnvironmentVariable("PATH"); + PythonEngine.Initialize(); } [OneTimeTearDown] From 38ef267a0613723929b39612b91acf9309e82cc1 Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Wed, 26 Jun 2019 13:11:06 -0700 Subject: [PATCH 4/5] mentioned enhancement of "No method matches given arguments" message in CHANGELONG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5531bf47..e5a990922 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. ### Changed +- Added argument types information to "No method matches given arguments" message + ### Fixed ## [2.4.0][] From 665b0153280da0c15650d8e04061d0d5366a9878 Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Wed, 26 Jun 2019 14:00:09 -0700 Subject: [PATCH 5/5] fixed TestNoOverloadException test failing on Python 2.x --- src/embed_tests/TestCallbacks.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/embed_tests/TestCallbacks.cs b/src/embed_tests/TestCallbacks.cs index 8cf698689..220b0a86a 100644 --- a/src/embed_tests/TestCallbacks.cs +++ b/src/embed_tests/TestCallbacks.cs @@ -4,6 +4,8 @@ using Python.Runtime; namespace Python.EmbeddingTest { + using Runtime = Python.Runtime.Runtime; + public class TestCallbacks { [OneTimeSetUp] public void SetUp() { @@ -23,7 +25,10 @@ public void TestNoOverloadException() { dynamic callWith42 = PythonEngine.Eval("lambda f: f([42])"); var error = Assert.Throws(() => callWith42(aFunctionThatCallsIntoPython.ToPython())); Assert.AreEqual("TypeError", error.PythonTypeName); - StringAssert.EndsWith("()", error.Message); + string expectedArgTypes = Runtime.IsPython2 + ? "()" + : "()"; + StringAssert.EndsWith(expectedArgTypes, error.Message); } } }