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][] diff --git a/src/embed_tests/TestCallbacks.cs b/src/embed_tests/TestCallbacks.cs new file mode 100644 index 000000000..220b0a86a --- /dev/null +++ b/src/embed_tests/TestCallbacks.cs @@ -0,0 +1,35 @@ +using System; + +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest { + using Runtime = Python.Runtime.Runtime; + + public class TestCallbacks { + [OneTimeSetUp] + public void SetUp() { + PythonEngine.Initialize(); + } + + [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); + string expectedArgTypes = Runtime.IsPython2 + ? "()" + : "()"; + StringAssert.EndsWith(expectedArgTypes, error.Message); + } + } + } +} diff --git a/src/runtime/methodbinder.cs b/src/runtime/methodbinder.cs index 7471d5d7c..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,12 +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}"); } - Exceptions.SetError(Exceptions.TypeError, value); + + long argCount = Runtime.PyTuple_Size(args); + 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) { + 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.Append(", "); + } + value.Append(')'); + Exceptions.SetError(Exceptions.TypeError, value.ToString()); return IntPtr.Zero; }