C# classes, which inherited __call__ from their Python base class, ar… · pythonnet/pythonnet@960457f
11using System;
2+using System.Diagnostics;
23using System.Reflection;
34using System.Runtime.InteropServices;
45@@ -299,17 +300,44 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw)
299300IntPtr methodObjectHandle = Runtime.PyDict_GetItemString(dict, "__call__");
300301if (methodObjectHandle == IntPtr.Zero || methodObjectHandle == Runtime.PyNone)
301302{
303+Runtime.XDecrefIgnoreNull(methodObjectHandle);
302304Exceptions.SetError(Exceptions.TypeError, "object is not callable");
303305return IntPtr.Zero;
304306}
305307306-if (GetManagedObject(methodObjectHandle) is MethodObject methodObject)
308+try
307309{
308-return methodObject.Invoke(ob, args, kw);
310+if (GetManagedObject(methodObjectHandle) is MethodObject methodObject)
311+{
312+return methodObject.Invoke(ob, args, kw);
313+}
314+315+IntPtr pythonBase = GetPythonBase(tp);
316+dict = Marshal.ReadIntPtr(pythonBase, TypeOffset.tp_dict);
317+Runtime.XDecref(methodObjectHandle);
318+methodObjectHandle = Runtime.PyDict_GetItemString(dict, "__call__");
319+if (methodObjectHandle == IntPtr.Zero || methodObjectHandle == Runtime.PyNone)
320+{
321+Exceptions.SetError(Exceptions.TypeError, "object is not callable");
322+return IntPtr.Zero;
323+}
324+325+var boundMethod = Runtime.PyMethod_New(methodObjectHandle, ob);
326+if (boundMethod == IntPtr.Zero) { return IntPtr.Zero; }
327+328+try
329+{
330+return Runtime.PyObject_Call(boundMethod, args, kw);
331+}
332+finally
333+{
334+Runtime.XDecref(boundMethod);
335+}
336+}
337+finally
338+{
339+Runtime.XDecrefIgnoreNull(methodObjectHandle);
309340}
310-311-Exceptions.SetError(Exceptions.TypeError, "instance has __call__, but it is not supported by Python.NET");
312-return IntPtr.Zero;
313341}
314342315343var co = (CLRObject)GetManagedObject(ob);
@@ -323,5 +351,24 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw)
323351var binder = new MethodBinder(method);
324352return binder.Invoke(ob, args, kw);
325353}
354+355+/// <summary>
356+/// Get the first base class in the class hierarchy
357+/// of the specified .NET type, that is defined in Python.
358+/// </summary>
359+static IntPtr GetPythonBase(IntPtr tp) {
360+Debug.Assert(IsManagedType(tp));
361+do {
362+tp = Marshal.ReadIntPtr(tp, TypeOffset.tp_base);
363+} while (IsManagedType(tp));
364+365+return tp;
366+}
367+368+internal static bool IsManagedType(IntPtr tp)
369+{
370+var flags = Util.ReadCLong(tp, TypeOffset.tp_flags);
371+return (flags & TypeFlags.Managed) != 0;
372+}
326373}
327374}