Skip to content

Commit df0574d

Browse files
lostmsufilmor
authored andcommitted
Improve "No method matches given arguments" message with more details (#900)
* generate more useful message, when a .NET overload can't be found, that matches Python parameter types * provide detailed error message, when an overload can't be found when calling C# from Python Related: #811, #265, #782
1 parent a8a9426 commit df0574d

File tree

3 files changed

+65
-3
lines changed

3 files changed

+65
-3
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
1313

1414
### Changed
1515

16+
- Added argument types information to "No method matches given arguments" message
17+
1618
### Fixed
1719

1820
## [2.4.0][]

src/embed_tests/TestCallbacks.cs

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System;
2+
3+
using NUnit.Framework;
4+
using Python.Runtime;
5+
6+
namespace Python.EmbeddingTest {
7+
using Runtime = Python.Runtime.Runtime;
8+
9+
public class TestCallbacks {
10+
[OneTimeSetUp]
11+
public void SetUp() {
12+
PythonEngine.Initialize();
13+
}
14+
15+
[OneTimeTearDown]
16+
public void Dispose() {
17+
PythonEngine.Shutdown();
18+
}
19+
20+
[Test]
21+
public void TestNoOverloadException() {
22+
int passed = 0;
23+
var aFunctionThatCallsIntoPython = new Action<int>(value => passed = value);
24+
using (Py.GIL()) {
25+
dynamic callWith42 = PythonEngine.Eval("lambda f: f([42])");
26+
var error = Assert.Throws<PythonException>(() => callWith42(aFunctionThatCallsIntoPython.ToPython()));
27+
Assert.AreEqual("TypeError", error.PythonTypeName);
28+
string expectedArgTypes = Runtime.IsPython2
29+
? "(<type 'list'>)"
30+
: "(<class 'list'>)";
31+
StringAssert.EndsWith(expectedArgTypes, error.Message);
32+
}
33+
}
34+
}
35+
}

src/runtime/methodbinder.cs

+28-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections;
33
using System.Reflection;
4+
using System.Text;
45

56
namespace Python.Runtime
67
{
@@ -555,12 +556,36 @@ internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, MethodBase i
555556

556557
if (binding == null)
557558
{
558-
var value = "No method matches given arguments";
559+
var value = new StringBuilder("No method matches given arguments");
559560
if (methodinfo != null && methodinfo.Length > 0)
560561
{
561-
value += $" for {methodinfo[0].Name}";
562+
value.Append($" for {methodinfo[0].Name}");
562563
}
563-
Exceptions.SetError(Exceptions.TypeError, value);
564+
565+
long argCount = Runtime.PyTuple_Size(args);
566+
value.Append(": (");
567+
for(long argIndex = 0; argIndex < argCount; argIndex++) {
568+
var arg = Runtime.PyTuple_GetItem(args, argIndex);
569+
if (arg != IntPtr.Zero) {
570+
var type = Runtime.PyObject_Type(arg);
571+
if (type != IntPtr.Zero) {
572+
try {
573+
var description = Runtime.PyObject_Unicode(type);
574+
if (description != IntPtr.Zero) {
575+
value.Append(Runtime.GetManagedString(description));
576+
Runtime.XDecref(description);
577+
}
578+
} finally {
579+
Runtime.XDecref(type);
580+
}
581+
}
582+
}
583+
584+
if (argIndex + 1 < argCount)
585+
value.Append(", ");
586+
}
587+
value.Append(')');
588+
Exceptions.SetError(Exceptions.TypeError, value.ToString());
564589
return IntPtr.Zero;
565590
}
566591

0 commit comments

Comments
 (0)