[pygobject] Remove PyGObjectWeakRef now that g_binding_unbind exists



commit 799989ada2f6b1d729f078f204445651c808a2c7
Author: Simon Feltman <sfeltman src gnome org>
Date:   Fri May 3 04:37:13 2013 -0700

    Remove PyGObjectWeakRef now that g_binding_unbind exists
    
    Remove the static code for managing GBinding weak references now that GLib
    has a method (unbind) for clearing out bindings.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=699571

 gi/_gobject/pygobject.c |   59 +----------------------------------------------
 gi/overrides/GObject.py |   19 +++++++++++++++
 tests/test_gobject.py   |   41 +++++++++++++++++++-------------
 3 files changed, 44 insertions(+), 75 deletions(-)
---
diff --git a/gi/_gobject/pygobject.c b/gi/_gobject/pygobject.c
index 65d5de9..c107a17 100644
--- a/gi/_gobject/pygobject.c
+++ b/gi/_gobject/pygobject.c
@@ -38,7 +38,6 @@ static int  pygobject_clear(PyGObject *self);
 static PyObject * pyg_type_get_bases(GType gtype);
 static inline int pygobject_clear(PyGObject *self);
 static PyObject * pygobject_weak_ref_new(GObject *obj, PyObject *callback, PyObject *user_data);
-static PyObject * pygbinding_weak_ref_new(GObject *obj);
 static inline PyGObjectData * pyg_object_peek_inst_data(GObject *obj);
 static void pygobject_inherit_slots(PyTypeObject *type, PyObject *bases,
                                    gboolean check_for_present);
@@ -1637,7 +1636,7 @@ pygobject_bind_property(PyGObject *self, PyObject *args)
                return NULL;
        }
 
-       return pygbinding_weak_ref_new(G_OBJECT (binding));
+       return pygobject_new (G_OBJECT (binding));
 }
 
 static PyObject *
@@ -2341,54 +2340,6 @@ pygobject_weak_ref_call(PyGObjectWeakRef *self, PyObject *args, PyObject *kw)
     }
 }
 
-
-/* -------------- GBinding Weak Reference ----------------- */
-
-/**
- * BindingWeakRef
- *
- * The BindingWeakRef object is used to manage GBinding objects within python
- * created through GObject.bind_property. It is a sub-class PyGObjectWeakRef so
- * that we can maintain the same reference counting semantics between Python
- * and GObject Binding objects. This gives explicit direct control of the
- * binding lifetime by using the "unbind" method on the BindingWeakRef object
- * along with implicit management based on the lifetime of the source or
- * target objects.
- */
-
-PYGLIB_DEFINE_TYPE("gi._gobject.GBindingWeakRef", PyGBindingWeakRef_Type, PyGObjectWeakRef);
-
-static PyObject *
-pygbinding_weak_ref_new(GObject *obj)
-{
-       PyGObjectWeakRef *self;
-
-       self = PyObject_GC_New(PyGObjectWeakRef, &PyGBindingWeakRef_Type);
-       self->callback = NULL;
-       self->user_data = NULL;
-       self->obj = obj;
-       g_object_weak_ref(self->obj, (GWeakNotify) pygobject_weak_ref_notify, self);
-       return (PyObject *) self;
-}
-
-static PyObject *
-pygbinding_weak_ref_unbind(PyGObjectWeakRef *self, PyObject *args)
-{
-    if (!self->obj) {
-        PyErr_SetString(PyExc_ValueError, "weak binding ref already unreffed");
-        return NULL;
-    }
-    g_object_unref(self->obj);
-    Py_INCREF(Py_None);
-    return Py_None;
-}
-
-static PyMethodDef pygbinding_weak_ref_methods[] = {
-    { "unbind", (PyCFunction)pygbinding_weak_ref_unbind, METH_NOARGS},
-    { NULL, NULL, 0}
-};
-
-
 static gpointer
 pyobject_copy(gpointer boxed)
 {
@@ -2494,12 +2445,4 @@ pygobject_object_register_types(PyObject *d)
     if (PyType_Ready(&PyGObjectWeakRef_Type) < 0)
         return;
     PyDict_SetItemString(d, "GObjectWeakRef", (PyObject *) &PyGObjectWeakRef_Type);
-
-    PyGBindingWeakRef_Type.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC;
-    PyGBindingWeakRef_Type.tp_doc = "A GBinding weak reference";
-    PyGBindingWeakRef_Type.tp_methods = pygbinding_weak_ref_methods;
-    PyGBindingWeakRef_Type.tp_base = &PyGObjectWeakRef_Type;
-    if (PyType_Ready(&PyGBindingWeakRef_Type) < 0)
-        return;
-    PyDict_SetItemString(d, "GBindingWeakRef", (PyObject *) &PyGBindingWeakRef_Type);
 }
diff --git a/gi/overrides/GObject.py b/gi/overrides/GObject.py
index b3aad47..07cb5bb 100644
--- a/gi/overrides/GObject.py
+++ b/gi/overrides/GObject.py
@@ -685,6 +685,25 @@ GObject = Object
 __all__ += ['Object', 'GObject']
 
 
+class Binding(GObjectModule.Binding):
+    def __call__(self):
+        warnings.warn('Using parentheses (binding()) to retrieve the Binding object is no '
+                      'longer needed because the binding is returned directly from "bind_property.',
+                      PyGIDeprecationWarning, stacklevel=2)
+        return self
+
+    def unbind(self):
+        if hasattr(self, '_unbound'):
+            raise ValueError('binding has already been cleared out')
+        else:
+            setattr(self, '_unbound', True)
+            super(Binding, self).unbind()
+
+
+Binding = override(Binding)
+__all__.append('Binding')
+
+
 Property = propertyhelper.Property
 Signal = signalhelper.Signal
 SignalOverride = signalhelper.SignalOverride
diff --git a/tests/test_gobject.py b/tests/test_gobject.py
index 57d3822..d49011f 100644
--- a/tests/test_gobject.py
+++ b/tests/test_gobject.py
@@ -415,6 +415,8 @@ class TestContextManagers(unittest.TestCase):
         self.assertEqual(self.tracking, [2])
 
 
+ unittest skipUnless(hasattr(GObject.Binding, 'unbind'),
+                     'Requires newer GLib which has g_binding_unbind')
 class TestPropertyBindings(unittest.TestCase):
     class TestObject(GObject.GObject):
         int_prop = GObject.Property(default=0, type=int)
@@ -509,8 +511,8 @@ class TestPropertyBindings(unittest.TestCase):
                                             GObject.BindingFlags.BIDIRECTIONAL,
                                             transform_to, transform_from, test_data)
         binding = binding  # PyFlakes
-        binding_ref_count = sys.getrefcount(binding())
-        binding_gref_count = binding().__grefcount__
+        binding_ref_count = sys.getrefcount(binding)
+        binding_gref_count = binding.__grefcount__
 
         self.source.int_prop = 1
         self.assertEqual(self.source.int_prop, 1)
@@ -520,8 +522,8 @@ class TestPropertyBindings(unittest.TestCase):
         self.assertEqual(self.source.int_prop, 2)
         self.assertEqual(self.target.int_prop, 4)
 
-        self.assertEqual(sys.getrefcount(binding()), binding_ref_count)
-        self.assertEqual(binding().__grefcount__, binding_gref_count)
+        self.assertEqual(sys.getrefcount(binding), binding_ref_count)
+        self.assertEqual(binding.__grefcount__, binding_gref_count)
 
         # test_data ref count increases by 2, once for each callback.
         self.assertEqual(sys.getrefcount(test_data), test_data_ref_count + 2)
@@ -530,9 +532,6 @@ class TestPropertyBindings(unittest.TestCase):
 
         # Unbind should clear out the binding and its transforms
         binding.unbind()
-        self.assertEqual(binding(), None)
-        del binding
-        gc.collect()
 
         # Setting source or target should not change the other.
         self.target.int_prop = 3
@@ -554,8 +553,9 @@ class TestPropertyBindings(unittest.TestCase):
         self.assertEqual(self.source.int_prop, 1)
         self.assertEqual(self.target.int_prop, 1)
 
+        # unbind should clear out the bindings self reference
         binding.unbind()
-        self.assertEqual(binding(), None)
+        self.assertEqual(binding.__grefcount__, 1)
 
         self.source.int_prop = 10
         self.assertEqual(self.source.int_prop, 10)
@@ -572,7 +572,7 @@ class TestPropertyBindings(unittest.TestCase):
         # the act of binding and the ref incurred by using __call__ to generate
         # a wrapper from the weak binding ref within python.
         binding = self.source.bind_property('int_prop', self.target, 'int_prop')
-        self.assertEqual(binding().__grefcount__, 2)
+        self.assertEqual(binding.__grefcount__, 2)
 
         # Creating a binding does not inc refs on source and target (they are weak
         # on the binding object itself)
@@ -581,18 +581,25 @@ class TestPropertyBindings(unittest.TestCase):
 
         # Use GObject.get_property because the "props" accessor leaks.
         # Note property names are canonicalized.
-        self.assertEqual(binding().get_property('source'), self.source)
-        self.assertEqual(binding().get_property('source_property'), 'int-prop')
-        self.assertEqual(binding().get_property('target'), self.target)
-        self.assertEqual(binding().get_property('target_property'), 'int-prop')
-        self.assertEqual(binding().get_property('flags'), GObject.BindingFlags.DEFAULT)
-
-        # Delete reference to source or target and the binding should listen.
+        self.assertEqual(binding.get_property('source'), self.source)
+        self.assertEqual(binding.get_property('source_property'), 'int-prop')
+        self.assertEqual(binding.get_property('target'), self.target)
+        self.assertEqual(binding.get_property('target_property'), 'int-prop')
+        self.assertEqual(binding.get_property('flags'), GObject.BindingFlags.DEFAULT)
+
+        # Delete reference to source or target and the binding will remove its own
+        # "self reference".
         ref = self.source.weak_ref()
         del self.source
         gc.collect()
         self.assertEqual(ref(), None)
-        self.assertEqual(binding(), None)
+        self.assertEqual(binding.__grefcount__, 1)
+
+        # Finally clear out the last ref held by the python wrapper
+        ref = binding.weak_ref()
+        del binding
+        gc.collect()
+        self.assertEqual(ref(), None)
 
 
 class TestGValue(unittest.TestCase):


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]