Skip to content

Commit 5cf42da

Browse files
committed
Move __init__ call in ClassDerived to tp_init.
1 parent 0dda85a commit 5cf42da

File tree

2 files changed

+81
-27
lines changed

2 files changed

+81
-27
lines changed

src/runtime/classderived.cs

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Reflection;
@@ -55,6 +55,33 @@ internal ClassDerivedObject(Type tp) : base(tp)
5555
return Converter.ToPython(obj, cls.GetType());
5656
}
5757

58+
public new static int tp_init(IntPtr obj, IntPtr args, IntPtr kw)
59+
{
60+
Runtime.XIncref(obj);
61+
Runtime.XIncref(Runtime.PyNone);
62+
using (var pyself = new PyObject(obj))
63+
using (var pynone = new PyObject(Runtime.PyNone))
64+
using (var init = pyself.GetAttr("__init__", pynone))
65+
{
66+
if (init.Handle != Runtime.PyNone)
67+
{
68+
// if __init__ hasn't been overridden then it will be a managed object
69+
if (GetManagedObject(init.Handle) == null)
70+
{
71+
Runtime.XIncref(args);
72+
Runtime.XIncref(kw);
73+
using (var args_ = new PyTuple(args))
74+
using (var kw_ = new PyDict(kw))
75+
using (var res = init.Invoke(args_, kw_))
76+
{
77+
}
78+
}
79+
}
80+
}
81+
82+
return 0;
83+
}
84+
5885
public new static void tp_dealloc(IntPtr ob)
5986
{
6087
var self = (CLRObject)GetManagedObject(ob);
@@ -801,6 +828,8 @@ public static void InvokeSetProperty<T>(IPythonDerivedType obj, string propertyN
801828

802829
public static void InvokeCtor(IPythonDerivedType obj, string origCtorName, object[] args)
803830
{
831+
Console.Error.WriteLine($"{origCtorName}: {string.Join(", ", args)}");
832+
804833
// call the base constructor
805834
obj.GetType().InvokeMember(origCtorName,
806835
BindingFlags.InvokeMethod,
@@ -822,33 +851,7 @@ public static void InvokeCtor(IPythonDerivedType obj, string origCtorName, objec
822851
FieldInfo fi = obj.GetType().GetField("__pyobj__");
823852
fi.SetValue(obj, self);
824853

825-
Runtime.XIncref(self.pyHandle);
826-
var pyself = new PyObject(self.pyHandle);
827-
disposeList.Add(pyself);
828-
829-
Runtime.XIncref(Runtime.PyNone);
830-
var pynone = new PyObject(Runtime.PyNone);
831-
disposeList.Add(pynone);
832854

833-
// call __init__
834-
PyObject init = pyself.GetAttr("__init__", pynone);
835-
disposeList.Add(init);
836-
if (init.Handle != Runtime.PyNone)
837-
{
838-
// if __init__ hasn't been overridden then it will be a managed object
839-
ManagedType managedMethod = ManagedType.GetManagedObject(init.Handle);
840-
if (null == managedMethod)
841-
{
842-
var pyargs = new PyObject[args.Length];
843-
for (var i = 0; i < args.Length; ++i)
844-
{
845-
pyargs[i] = new PyObject(Converter.ToPython(args[i], args[i]?.GetType()));
846-
disposeList.Add(pyargs[i]);
847-
}
848-
849-
disposeList.Add(init.Invoke(pyargs));
850-
}
851-
}
852855
}
853856
finally
854857
{

src/runtime/metatype.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,57 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw)
125125
}
126126

127127

128+
/// <summary>
129+
/// Metatype __call__ implementation. This is needed to ensure correct
130+
/// initialization (__init__ support), because the tp_call we inherit
131+
/// from PyType_Type won't call __init__ for metatypes it doesn't know.
132+
/// </summary>
133+
public static IntPtr tp_call(IntPtr tp, IntPtr args, IntPtr kw)
134+
{
135+
IntPtr func = Marshal.ReadIntPtr(tp, TypeOffset.tp_new);
136+
if (func == IntPtr.Zero)
137+
{
138+
return Exceptions.RaiseTypeError("invalid object");
139+
}
140+
141+
IntPtr obj = NativeCall.Call_3(func, tp, args, kw);
142+
if (obj == IntPtr.Zero)
143+
{
144+
return IntPtr.Zero;
145+
}
146+
147+
IntPtr py__init__ = Runtime.PyString_FromString("__init__");
148+
IntPtr type = Runtime.PyObject_TYPE(obj);
149+
IntPtr init = Runtime._PyType_Lookup(type, py__init__);
150+
Runtime.XDecref(py__init__);
151+
Runtime.PyErr_Clear();
152+
153+
if (init != IntPtr.Zero)
154+
{
155+
IntPtr bound = Runtime.GetBoundArgTuple(obj, args);
156+
if (bound == IntPtr.Zero)
157+
{
158+
Runtime.XDecref(obj);
159+
return IntPtr.Zero;
160+
}
161+
162+
IntPtr result = Runtime.PyObject_Call(init, bound, kw);
163+
Runtime.XDecref(bound);
164+
165+
if (result == IntPtr.Zero)
166+
{
167+
Runtime.XDecref(obj);
168+
return IntPtr.Zero;
169+
}
170+
171+
Runtime.XDecref(result);
172+
}
173+
174+
return obj;
175+
}
176+
177+
178+
128179
public static IntPtr tp_alloc(IntPtr mt, int n)
129180
{
130181
IntPtr type = Runtime.PyType_GenericAlloc(mt, n);

0 commit comments

Comments
 (0)