Skip to content

Commit 61478ef

Browse files
committed
improved documentation for MethodBinding
1 parent bc7aa20 commit 61478ef

File tree

2 files changed

+35
-6
lines changed

2 files changed

+35
-6
lines changed

src/runtime/methodbinding.cs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,23 +63,26 @@ public static IntPtr mp_subscript(IntPtr tp, IntPtr idx)
6363
PyObject Singature {
6464
get {
6565
var infos = this.info == null ? this.m.info : new[] {this.info};
66+
var type = infos.Select(i => i.DeclaringType)
67+
.OrderByDescending(t => t, new TypeSpecificityComparer())
68+
.First();
69+
infos = infos.Where(info => info.DeclaringType == type).ToArray();
6670
// this is a primitive version
6771
// the overload with the maximum number of parameters should be used
68-
var primary = infos.First();
72+
var primary = infos.OrderByDescending(i => i.GetParameters().Length).First();
6973
var primaryParameters = primary.GetParameters();
7074
PyObject signatureClass = Runtime.InspectModule.GetAttr("Signature");
7175
var primaryReturn = primary.ReturnParameter;
72-
if (infos.Any(i => i.GetParameters().Length != primaryParameters.Length
73-
|| i.ReturnParameter?.ParameterType != primaryReturn?.ParameterType)) {
74-
return signatureClass.Invoke();
75-
}
7676

7777
var parameters = new PyList();
7878
var parameterClass = primaryParameters.Length > 0 ? Runtime.InspectModule.GetAttr("Parameter") : null;
7979
var positionalOrKeyword = primaryParameters.Length > 0 ? parameterClass.GetAttr("POSITIONAL_OR_KEYWORD") : null;
8080
for (int i = 0; i < primaryParameters.Length; i++) {
8181
var parameter = primaryParameters[i];
82-
var alternatives = infos.Select(info => info.GetParameters()[i]);
82+
var alternatives = infos.Select(info => {
83+
ParameterInfo[] altParamters = info.GetParameters();
84+
return i < altParamters.Length ? altParamters[i] : null;
85+
}).Where(p => p != null);
8386
var defaultValue = alternatives
8487
.Select(alternative => alternative.DefaultValue != DBNull.Value ? alternative.DefaultValue.ToPython() : null)
8588
.FirstOrDefault(v => v != null) ?? parameterClass.GetAttr("empty");
@@ -102,6 +105,15 @@ PyObject Singature {
102105
}
103106
}
104107

108+
struct TypeSpecificityComparer : IComparer<Type> {
109+
public int Compare(Type a, Type b) {
110+
if (a == b) return 0;
111+
if (a.IsSubclassOf(b)) return 1;
112+
if (b.IsSubclassOf(a)) return -1;
113+
throw new NotSupportedException();
114+
}
115+
}
116+
105117
/// <summary>
106118
/// MethodBinding __getattribute__ implementation.
107119
/// </summary>
@@ -130,6 +142,11 @@ public static IntPtr tp_getattro(IntPtr ob, IntPtr key)
130142
case "__signature__":
131143
var sig = self.Singature;
132144
return sig.Handle;
145+
case "__name__":
146+
var pyName = self.m.GetName();
147+
return pyName == IntPtr.Zero
148+
? IntPtr.Zero
149+
: Runtime.SelfIncRef(pyName);
133150
default:
134151
return Runtime.PyObject_GenericGetAttr(ob, key);
135152
}

src/runtime/methodobject.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
24
using System.Reflection;
35

46
namespace Python.Runtime
@@ -90,6 +92,16 @@ internal IntPtr GetDocString()
9092
return doc;
9193
}
9294

95+
internal IntPtr GetName()
96+
{
97+
var names = new HashSet<string>(binder.GetMethods().Select(m => m.Name));
98+
if (names.Count != 1) {
99+
Exceptions.SetError(Exceptions.AttributeError, "a method has no name");
100+
return IntPtr.Zero;
101+
}
102+
return Runtime.PyString_FromString(names.First());
103+
}
104+
93105

94106
/// <summary>
95107
/// This is a little tricky: a class can actually have a static method

0 commit comments

Comments
 (0)