diff --git a/src/embed_tests/ExtensionTypes.cs b/src/embed_tests/ExtensionTypes.cs new file mode 100644 index 000000000..803845960 --- /dev/null +++ b/src/embed_tests/ExtensionTypes.cs @@ -0,0 +1,32 @@ +using System; + +using NUnit.Framework; + +using Python.Runtime; + +namespace Python.EmbeddingTest; + +public class ExtensionTypes +{ + [OneTimeSetUp] + public void SetUp() + { + PythonEngine.Initialize(); + } + + [OneTimeTearDown] + public void Dispose() + { + PythonEngine.Shutdown(); + } + + [Test] + public void WeakrefIsNone_AfterBoundMethodIsGone() + { + using var makeref = Py.Import("weakref").GetAttr("ref"); + var boundMethod = new UriBuilder().ToPython().GetAttr(nameof(UriBuilder.GetHashCode)); + var weakref = makeref.Invoke(boundMethod); + boundMethod.Dispose(); + Assert.IsTrue(weakref.Invoke().IsNone()); + } +} diff --git a/src/runtime/Types/ExtensionType.cs b/src/runtime/Types/ExtensionType.cs index d680067c2..439bd3314 100644 --- a/src/runtime/Types/ExtensionType.cs +++ b/src/runtime/Types/ExtensionType.cs @@ -86,6 +86,12 @@ public unsafe static void tp_dealloc(NewReference lastRef) public static int tp_clear(BorrowedReference ob) { + var weakrefs = Runtime.PyObject_GetWeakRefList(ob); + if (weakrefs != null) + { + Runtime.PyObject_ClearWeakRefs(ob); + } + if (TryFreeGCHandle(ob)) { bool deleted = loadedExtensions.Remove(ob.DangerousGetAddress()); diff --git a/src/runtime/Types/MetaType.cs b/src/runtime/Types/MetaType.cs index 7558269b4..1543711f6 100644 --- a/src/runtime/Types/MetaType.cs +++ b/src/runtime/Types/MetaType.cs @@ -273,6 +273,12 @@ public static NewReference mp_subscript(BorrowedReference tp, BorrowedReference /// public static void tp_dealloc(NewReference lastRef) { + var weakrefs = Runtime.PyObject_GetWeakRefList(lastRef.Borrow()); + if (weakrefs != null) + { + Runtime.PyObject_ClearWeakRefs(lastRef.Borrow()); + } + // Fix this when we dont cheat on the handle for subclasses! var flags = PyType.GetFlags(lastRef.Borrow());