C# classes, which inherited __call__ from their Python base class, ar… · pythonnet/pythonnet@960457f

11

using System;

2+

using System.Diagnostics;

23

using System.Reflection;

34

using System.Runtime.InteropServices;

45

@@ -299,17 +300,44 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw)

299300

IntPtr methodObjectHandle = Runtime.PyDict_GetItemString(dict, "__call__");

300301

if (methodObjectHandle == IntPtr.Zero || methodObjectHandle == Runtime.PyNone)

301302

{

303+

Runtime.XDecrefIgnoreNull(methodObjectHandle);

302304

Exceptions.SetError(Exceptions.TypeError, "object is not callable");

303305

return 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

}

314342315343

var co = (CLRObject)GetManagedObject(ob);

@@ -323,5 +351,24 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw)

323351

var binder = new MethodBinder(method);

324352

return 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

}