Fix kwarg func resolution by jmlidbetter · Pull Request #1136 · pythonnet/pythonnet
private readonly struct MatchedMethod { public MatchedMethod(int kwargsMatched, int defaultsNeeded, object[] margs, int outs, MethodBase mb) { KwargsMatched = kwargsMatched; DefaultsNeeded = defaultsNeeded; ManagedArgs = margs; Outs = outs; Method = mb; }
public int KwargsMatched { get; } public int DefaultsNeeded { get; } public object[] ManagedArgs { get; } public int Outs { get; } public MethodBase Method { get; } }
internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, MethodInfo[] methodinfo) { // loop to find match, return invoker w/ or /wo error
var argMatchedMethods = new List<MatchedMethod>(_methods.Length);
// TODO: Clean up foreach (MethodBase mi in _methods) {
if (!MatchesArgumentCount(pynargs, pi, kwargDict, out paramsArray, out defaultArgList)) if (!MatchesArgumentCount(pynargs, pi, kwargDict, out paramsArray, out defaultArgList, out kwargsMatched, out defaultsNeeded)) { continue; }
var matchedMethod = new MatchedMethod(kwargsMatched, defaultsNeeded, margs, outs, mi); argMatchedMethods.Add(matchedMethod); } if (argMatchedMethods.Count > 0) { var bestKwargMatchCount = argMatchedMethods.Max(x => x.KwargsMatched); var fewestDefaultsRequired = argMatchedMethods.Where(x => x.KwargsMatched == bestKwargMatchCount).Min(x => x.DefaultsNeeded);
int bestCount = 0; int bestMatchIndex = -1;
for (int index = 0; index < argMatchedMethods.Count; index++) { var testMatch = argMatchedMethods[index]; if (testMatch.DefaultsNeeded == fewestDefaultsRequired && testMatch.KwargsMatched == bestKwargMatchCount) { bestCount++; if (bestMatchIndex == -1) bestMatchIndex = index; } }
if (bestCount > 1 && fewestDefaultsRequired > 0) { // Best effort for determining method to match on gives multiple possible // matches and we need at least one default argument - bail from this point return null; }
// If we're here either: // (a) There is only one best match // (b) There are multiple best matches but none of them require // default arguments // in the case of (a) we're done by default. For (b) regardless of which // method we choose, all arguments are specified _and_ can be converted // from python to C# so picking any will suffice MatchedMethod bestMatch = argMatchedMethods[bestMatchIndex]; var margs = bestMatch.ManagedArgs; var outs = bestMatch.Outs; var mi = bestMatch.Method;
object target = null; if (!mi.IsStatic && inst != IntPtr.Zero) {
if (positionalArgumentCount == parameters.Length && kwargDict.Count == 0) {