Skip to content

Commit 9f64f56

Browse files
committed
Drop tp_call implementation from metatype.
This seems to be a patch for broken behaviour in Python. Removing it should solve #495 (`__init__` called twice on construction).
1 parent 12af794 commit 9f64f56

File tree

2 files changed

+19
-52
lines changed

2 files changed

+19
-52
lines changed

src/runtime/metatype.cs

+1-52
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Runtime.InteropServices;
33

44
namespace Python.Runtime
@@ -137,57 +137,6 @@ public static void tp_free(IntPtr tp)
137137
Runtime.PyObject_GC_Del(tp);
138138
}
139139

140-
141-
/// <summary>
142-
/// Metatype __call__ implementation. This is needed to ensure correct
143-
/// initialization (__init__ support), because the tp_call we inherit
144-
/// from PyType_Type won't call __init__ for metatypes it doesn't know.
145-
/// </summary>
146-
public static IntPtr tp_call(IntPtr tp, IntPtr args, IntPtr kw)
147-
{
148-
IntPtr func = Marshal.ReadIntPtr(tp, TypeOffset.tp_new);
149-
if (func == IntPtr.Zero)
150-
{
151-
return Exceptions.RaiseTypeError("invalid object");
152-
}
153-
154-
IntPtr obj = NativeCall.Call_3(func, tp, args, kw);
155-
if (obj == IntPtr.Zero)
156-
{
157-
return IntPtr.Zero;
158-
}
159-
160-
IntPtr py__init__ = Runtime.PyString_FromString("__init__");
161-
IntPtr type = Runtime.PyObject_TYPE(obj);
162-
IntPtr init = Runtime._PyType_Lookup(type, py__init__);
163-
Runtime.XDecref(py__init__);
164-
Runtime.PyErr_Clear();
165-
166-
if (init != IntPtr.Zero)
167-
{
168-
IntPtr bound = Runtime.GetBoundArgTuple(obj, args);
169-
if (bound == IntPtr.Zero)
170-
{
171-
Runtime.XDecref(obj);
172-
return IntPtr.Zero;
173-
}
174-
175-
IntPtr result = Runtime.PyObject_Call(init, bound, kw);
176-
Runtime.XDecref(bound);
177-
178-
if (result == IntPtr.Zero)
179-
{
180-
Runtime.XDecref(obj);
181-
return IntPtr.Zero;
182-
}
183-
184-
Runtime.XDecref(result);
185-
}
186-
187-
return obj;
188-
}
189-
190-
191140
/// <summary>
192141
/// Type __setattr__ implementation for reflected types. Note that this
193142
/// is slightly different than the standard setattr implementation for

src/tests/test_subclass.py

+18
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,21 @@ def test_isinstance_check():
190190
for x in b:
191191
assert isinstance(x, System.Object)
192192
assert isinstance(x, System.String)
193+
194+
195+
_derived_cons_calls = 0
196+
197+
def test_derived_constructor_only_called_once():
198+
global _derived_cons_calls
199+
_derived_cons_calls = 0
200+
201+
class X(System.Object):
202+
__namespace__ = "PyTest"
203+
204+
def __init__(self):
205+
global _derived_cons_calls
206+
_derived_cons_calls += 1
207+
208+
x = X()
209+
210+
assert _derived_cons_calls == 1

0 commit comments

Comments
 (0)