Skip to content

Commit 4fe93c4

Browse files
Merge branch 'fix-init' of github.com:rickardraysearch/pythonnet into fix-init
2 parents 14cdbef + f72c8cc commit 4fe93c4

File tree

5 files changed

+33
-49
lines changed

5 files changed

+33
-49
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
2222
attribute (#481)
2323
- Fixed conversion of 'float' and 'double' values (#486)
2424
- Fixed 'clrmethod' for python 2 (#492)
25+
- Fixed double calling of constructor when deriving from .NET class (#495)
2526

2627

2728
## [2.3.0][] - 2017-03-11

src/runtime/classderived.cs

-14
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,6 @@ public static void InvokeCtor(IPythonDerivedType obj, string origCtorName, objec
808808
obj,
809809
args);
810810

811-
var disposeList = new List<PyObject>();
812811
CLRObject self = null;
813812
IntPtr gs = Runtime.PyGILState_Ensure();
814813
try
@@ -821,22 +820,9 @@ public static void InvokeCtor(IPythonDerivedType obj, string origCtorName, objec
821820
// object to be collected.
822821
FieldInfo fi = obj.GetType().GetField("__pyobj__");
823822
fi.SetValue(obj, self);
824-
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);
832823
}
833824
finally
834825
{
835-
foreach (PyObject x in disposeList)
836-
{
837-
x?.Dispose();
838-
}
839-
840826
// Decrement the python object's reference count.
841827
// This doesn't actually destroy the object, it just sets the reference to this object
842828
// to be a weak reference and it will be destroyed when the C# object is destroyed.

src/runtime/metatype.cs

+2-9
Original file line numberDiff line numberDiff line change
@@ -162,15 +162,8 @@ public static IntPtr tp_call(IntPtr tp, IntPtr args, IntPtr kw)
162162

163163
if (init != IntPtr.Zero)
164164
{
165-
IntPtr bound = Runtime.GetBoundArgTuple(obj, args);
166-
if (bound == IntPtr.Zero)
167-
{
168-
Runtime.XDecref(obj);
169-
return IntPtr.Zero;
170-
}
171-
172-
IntPtr result = Runtime.PyObject_Call(init, bound, kw);
173-
Runtime.XDecref(bound);
165+
IntPtr result = Runtime.PyObject_Call(init, args, kw);
166+
Runtime.XDecref(init);
174167

175168
if (result == IntPtr.Zero)
176169
{

src/runtime/runtime.cs

-23
Original file line numberDiff line numberDiff line change
@@ -378,29 +378,6 @@ internal static void CheckExceptionOccurred()
378378
}
379379
}
380380

381-
internal static IntPtr GetBoundArgTuple(IntPtr obj, IntPtr args)
382-
{
383-
if (PyObject_TYPE(args) != PyTupleType)
384-
{
385-
Exceptions.SetError(Exceptions.TypeError, "tuple expected");
386-
return IntPtr.Zero;
387-
}
388-
int size = PyTuple_Size(args);
389-
IntPtr items = PyTuple_New(size + 1);
390-
PyTuple_SetItem(items, 0, obj);
391-
XIncref(obj);
392-
393-
for (var i = 0; i < size; i++)
394-
{
395-
IntPtr item = PyTuple_GetItem(args, i);
396-
XIncref(item);
397-
PyTuple_SetItem(items, i + 1, item);
398-
}
399-
400-
return items;
401-
}
402-
403-
404381
internal static IntPtr ExtendTuple(IntPtr t, params IntPtr[] args)
405382
{
406383
int size = PyTuple_Size(t);

src/tests/test_subclass.py

+30-3
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ def test_isinstance_check():
191191
assert isinstance(x, System.Object)
192192
assert isinstance(x, System.String)
193193

194-
def test_clr_subclass_with_init_args():
194+
def test_namespace_and_init():
195195
calls = []
196196
class TestX(System.Object):
197197
__namespace__ = "test_clr_subclass_with_init_args"
@@ -202,7 +202,7 @@ def __init__(self, *args, **kwargs):
202202
assert calls[0][0] == (1,2,3)
203203
assert calls[0][1] == {"foo":"bar"}
204204

205-
def test_clr_subclass_without_init_args():
205+
def test_namespace_and_argless_init():
206206
calls = []
207207
class TestX(System.Object):
208208
__namespace__ = "test_clr_subclass_without_init_args"
@@ -213,9 +213,36 @@ def __init__(self):
213213
assert calls[0] == True
214214

215215

216-
def test_clr_subclass_without_init():
216+
def test_namespace_and_no_init():
217217
class TestX(System.Object):
218218
__namespace__ = "test_clr_subclass_without_init"
219219
q = 1
220220
t = TestX()
221221
assert t.q == 1
222+
223+
def test_construction_from_clr():
224+
import clr
225+
calls = []
226+
class TestX(System.Object):
227+
__namespace__ = "test_clr_subclass_init_from_clr"
228+
@clr.clrmethod(None, [int, str])
229+
def __init__(self, i, s):
230+
calls.append((i, s))
231+
232+
# Construct a TestX from Python
233+
t = TestX(1, "foo")
234+
assert len(calls) == 1
235+
assert calls[0][0] == 1
236+
assert calls[0][1] == "foo"
237+
238+
# Reset calls and construct a TestX from CLR
239+
calls = []
240+
tp = t.GetType()
241+
t2 = tp.GetConstructors()[0].Invoke(None)
242+
assert len(calls) == 0
243+
244+
# The object has only been constructed, now it needs to be initialized as well
245+
tp.GetMethod("__init__").Invoke(t2, [1, "foo"])
246+
assert len(calls) == 1
247+
assert calls[0][0] == 1
248+
assert calls[0][1] == "foo"

0 commit comments

Comments
 (0)