10000 Weakref support by amos402 · Pull Request #1267 · pythonnet/pythonnet · GitHub
[go: up one dir, main page]

Skip to content

Weakref support #1267

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 13 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/embed_tests/Python.EmbeddingTest.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
Expand Down Expand Up @@ -90,6 +90,7 @@
<Compile Include="pyinitialize.cs" />
<Compile Include="pyrunstring.cs" />
<Compile Include="References.cs" />
<Compile Include="TestClass.cs" />
<Compile Include="TestConverter.cs" />
<Compile Include="TestCustomMarshal.cs" />
<Compile Include="TestDomainReload.cs" />
Expand Down
82 changes: 82 additions & 0 deletions src/embed_tests/TestClass.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System;
using System.Runtime.InteropServices;

using NUnit.Framework;

using Python.Runtime;

using PyRuntime = Python.Runtime.Runtime;

namespace Python.EmbeddingTest
{
public class TestClass
{
public class MyClass
{
}

[OneTimeSetUp]
public void SetUp()
{
PythonEngine.Initialize();
}

[OneTimeTearDown]
public void Dispose()
{
PythonEngine.Shutdown();
}

[Test]
public void WeakRefForClrObject()
{
var obj = new MyClass();
using (var scope = Py.CreateScope())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: use C# 9 using syntax

{
scope.Set("clr_obj", obj);
scope.Exec(@"
import weakref
ref = weakref.ref(clr_obj)
");
using (PyObject pyobj = scope.Get("clr_obj"))
{
ValidateAttachedGCHandle(obj, pyobj.Handle);
}
}
}

[Test]
public void WeakRefForSubClass()
{
using (var scope = Py.CreateScope())
{
scope.Exec(@"
from Python.EmbeddingTest import TestClass
import weakref

class Sub(TestClass.MyClass):
pass

obj = Sub()
ref = weakref.ref(obj)
");
using (PyObject pyobj = scope.Get("obj"))
{
IntPtr op = pyobj.Handle;
IntPtr type = PyRuntime.PyObject_TYPE(op);
IntPtr clrHandle = Marshal.ReadIntPtr(op, ObjectOffset.magic(type));
var clobj = (CLRObject)GCHandle.FromIntPtr(clrHandle).Target;
Assert.IsTrue(clobj.inst is MyClass);
}
}
}

private static void ValidateAttachedGCHandle(object obj, IntPtr op)
{
IntPtr type = PyRuntime.PyObject_TYPE(op);
IntPtr clrHandle = Mars 8000 hal.ReadIntPtr(op, ObjectOffset.magic(type));
var clobj = (CLRObject)GCHandle.FromIntPtr(clrHandle).Target;
Assert.True(ReferenceEquals(clobj.inst, obj));
}
}
}
36 changes: 15 additions & 21 deletions src/runtime/classbase.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;

namespace Python.Runtime
{
Expand Down Expand Up @@ -303,44 +301,40 @@ public static IntPtr tp_repr(IntPtr ob)
public static void tp_dealloc(IntPtr ob)
{
ManagedType self = GetManagedObject(ob);
if (Runtime.PyType_SUPPORTS_WEAKREFS(Runtime.PyObject_TYPE(ob)))
{
Runtime.PyObject_ClearWeakRefs(ob);
}
tp_clear(ob);
Runtime.PyObject_GC_UnTrack(self.pyHandle);
Runtime.PyObject_GC_Del(self.pyHandle);
Runtime.PyObject_GC_UnTrack(ob);
Runtime.PyObject_GC_Del(ob);
self.FreeGCHandle();
}

public static int tp_clear(IntPtr ob)
{
ManagedType self = GetManagedObject(ob);
if (!self.IsTypeObject())
{
ClearObjectDict(ob);
}
self.tpHandle = IntPtr.Zero;
ClearObjectDict(ob);
Runtime.Py_CLEAR(ref self.tpHandle);
return 0;
}

protected override void OnSave(InterDomainContext context)
{
base.OnSave(context);
if (pyHandle != tpHandle)
{
IntPtr dict = GetObjectDict(pyHandle);
Runtime.XIncref(dict);
context.Storage.AddValue("dict", dict);
}
IntPtr dict = GetObjectDict(pyHandle);
Runtime.XIncref(dict);
Runtime.XIncref(tpHandle);
context.Storage.AddValue("dict", dict);
}

protected override void OnLoad(InterDomainContext context)
{
base.OnLoad(context);
if (pyHandle != tpHandle)
{
IntPtr dict = context.Storage.GetValue<IntPtr>("dict");
SetObjectDict(pyHandle, dict);
}
IntPtr dict = context.Storage.GetValue<IntPtr>("dict");
SetObjectDict(pyHandle, dict);
gcHandle = AllocGCHandle();
Marshal.WriteIntPtr(pyHandle, TypeOffset.magic(), (IntPtr)gcHandle);
Marshal.WriteIntPtr(pyHandle, ObjectOffset.magic(tpHandle), (IntPtr)gcHandle);
}


Expand Down
1 change: 1 addition & 0 deletions src/runtime/classmanager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ private static ClassInfo GetClassInfo(Type type)
}
// Note the given instance might be uninitialized
ob = GetClass(tp);
ob.IncrRefCount();
ci.members[mi.Name] = ob;
continue;
}
Expand Down
8 changes: 2 additions & 6 deletions src/runtime/clrobject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@ internal CLRObject(object ob, IntPtr tp)
tpHandle = tp;
pyHandle = py;
inst = ob;

// Fix the BaseException args (and __cause__ in case of Python 3)
// slot if wrapping a CLR exception
Exceptions.SetArgsAndCause(py);
}

protected CLRObject()
Expand All @@ -48,7 +44,7 @@ static CLRObject GetInstance(object ob, IntPtr pyType)
static CLRObject GetInstance(object ob)
{
ClassBase cc = ClassManager.GetClass(ob.GetType());
return GetInstance(ob, cc.tpHandle);
return GetInstance(ob, cc.pyHandle);
}


Expand All @@ -62,7 +58,7 @@ internal static IntPtr GetInstHandle(object ob, IntPtr pyType)
internal static IntPtr GetInstHandle(object ob, Type type)
{
ClassBase cc = ClassManager.GetClass(type);
CLRObject co = GetInstance(ob, cc.tpHandle);
CLRObject co = GetInstance(ob, cc.pyHandle);
return co.pyHandle;
}

Expand Down
25 changes: 20 additions & 5 deletions src/runtime/exceptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ internal static Exception ToException(IntPtr ob)
}
return Runtime.PyUnicode_FromString(message);
}

public static int tp_init(IntPtr ob, IntPtr args, IntPtr kwds)
{
Exceptions.SetArgsAndCause(ob);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, move the original comment here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What comment?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: You seem to have moved this from CLRObject, and removed

// Fix the BaseException args (and __cause__ in case of Python 3)
// slot if wrapping a CLR exception

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment on SetArgsAndCause won't be enough?

return 0;
}

}

/// <summary>
Expand Down Expand Up @@ -177,15 +184,23 @@ internal static void SetArgsAndCause(IntPtr ob)
args = Runtime.PyTuple_New(0);
}

Marshal.WriteIntPtr(ob, ExceptionOffset.args, args);

int baseOffset = OriginalObjectOffsets.Size;
Runtime.Py_SETREF(ob, baseOffset + ExceptionOffset.args, args);

if (e.InnerException != null)
{
IntPtr cause = CLRObject.GetInstHandle(e.InnerException);
Marshal.WriteIntPtr(ob, ExceptionOffset.cause, cause);
IntPtr cause = GetExceptHandle(e.InnerException);
Runtime.Py_SETREF(ob, baseOffset + ExceptionOffset.cause, cause);
}
}

internal static IntPtr GetExceptHandle(Exception e)
{
IntPtr op = CLRObject.GetInstHandle(e);
SetArgsAndCause(op);
return op;
}

/// <summary>
/// Shortcut for (pointer == NULL) -&gt; throw PythonException
/// </summary>
Expand Down Expand Up @@ -283,7 +298,7 @@ public static void SetError(Exception e)
return;
}

IntPtr op = CLRObject.GetInstHandle(e);
IntPtr op = GetExceptHandle(e);
IntPtr etype = Runtime.PyObject_GetAttrString(op, "__class__");
Runtime.PyErr_SetObject(new BorrowedReference(etype), new BorrowedReference(op));
Runtime.XDecref(etype);
Expand Down
Loading
0