After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 332782 - Add signal connection reference management
Add signal connection reference management
Status: RESOLVED OBSOLETE
Product: pygobject
Classification: Bindings
Component: gobject
unspecified
Other Linux
: Low enhancement
: ---
Assigned To: Nobody's working on this now (help wanted and appreciated)
Python bindings maintainers
Depends on: 672727
Blocks:
 
 
Reported: 2006-02-27 20:47 UTC by Tiago Cogumbreiro
Modified: 2018-01-10 19:57 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description Tiago Cogumbreiro 2006-02-27 20:47:04 UTC
I've created an implementation[1] based on a document I wrote[2].

Basically it represents a signal connection with an instance. When that instance has no references left the connection is terminated. The connection is also terminated when the object is destroyed (and the 'destroy' signal is emitted).

[1] - http://linus.uac.pt/~cogumbreiro/signalholder.py
[2] - http://s1x.homelinux.net/documents/subscription_en
Comment 1 Simon van der Linden 2009-03-20 22:38:36 UTC
The links are broken.
Comment 2 Tiago Cogumbreiro 2009-04-22 20:37:49 UTC
The new links are:

[1] - http://cogumbreiro.googlecode.com/svn/trunk/python/signalholder.py
[2] - http://irrepupavel.com/documents/subscription_en/

Since this is the only reason the bug was closed, I have reopened it.
Comment 3 Johan (not receiving bugmail) Dahlin 2009-04-23 01:44:27 UTC
This makes some sense, a bit of extra work but the API will definitely be nicer.

Would also be good if a group of signals can be bound together, so you can disconnect/block all of them at the same time.

Maybe something like this:

  connection = obj.connect('foo', cb).connect('bar', cb)
  connection.disconnect()

Eg, GObject.connect() returns a SignalConnection which also has a connect() method.
Comment 4 Simon Feltman 2012-03-15 23:41:35 UTC
A Connection type of object returned from GObject.connect would be very nice. The Connection object should also not auto disconnect in its __del__ method as this is implicit and would break existing code. Currently I have to track both the object and id of connections, a single connection object would be much cleaner. It can also easily maintain backwards compatibility:
  connection = obj.connect('foo', cb)
  obj.disconnect(connection)
  # or
  connection.disconnect()

Auto disconnecting signals also has much utility, but should be specified explicitly when connecting:
  connection = obj.connect_weak('foo', cb)

However, I think the callback "cb" is what should be weakly referenced and when the callback is deleted, then the connection to it is removed, not the connection object being deleted. With that in mind something like this can work well in practice:
  
  class Foo(object):
    def onBaz(self, obj):
      pass
  foo = Foo()
  bar.connect_weak('baz', foo.onBaz)
  del foo # also disconnects foo.onBaz which would normally be kept around
Comment 5 Simon Feltman 2012-11-11 08:10:54 UTC
I changed the title of this to be a little more generic so we can include discussion of other techniques. I am assuming the goal is generally a technique for better management or auto management of signal callbacks in python.

In C, the g_signal_connect_object function is what this is all about. The function ties the lifetime of the signal to that of the object argument passed in and automatically disconnects it when the object is fully un-reffed. This behavior is not observed in the pygobject static bindings as outlined in bug 688064.

Even with bug 688064 fixed, there are more common use cases in the python world than connect_object allows for. A few use cases with possible solutions:


Connecting lambdas or partials:
 button.connect('pressed', lambda btn: obj.callback(myarg))

In this case a strong ref to the lambda would be needed as it is a temporary in the python code. This could be supported based on the originally proposed idea of having the signal connection tied to the lifetime of the return result (SignalHolder). This would need a separate explicit method because replacing the existing "connect" method would break everything. Something like:
 connection = button.connect_weak_result('pressed', lambda btn: obj.callback(myarg))
or:
 connection = WeakConnection(button.connect('pressed', lambda btn: obj.callback(myarg)))


Connecting a bound method:
 button.connect('pressed', obj.callback)

The issue with this is that obj will be kept alive by the connection even when all references to it in python are removed. The connection must then be manually disconnected using an id. So a controller object making the connection needs to keep references to both the button and the connection id and then manually disconnect these in some type of shutdown method. This could potentially be resolved if bug 688064 is fixed but requires shifting of the code and the object argument must be a GObject, not an arbitrary python object:
 button.connect_object('pressed', CustomGObject.callback, obj)

To get around the issue of only supporting GObjects for the lifetime of the connection, connect_object could be overridden to use the ref-count of the python object instead which would support GObjects and any arbitrary python object. However, I think direct support of weakly referenced objects and bound methods as arguments is ideal here. In which case we could have something like:
 button.connect_weak('pressed', obj.callback)


If pygobject does not directly provide solutions to these use cases (I consider them common enough for inclusion), then minimally we need documentation which gives recipes for how to achieve these use cases.
Comment 6 Simon Feltman 2012-11-11 10:00:48 UTC
I also logged this as I think it is about time python included support for weakrefs to bound methods: http://bugs.python.org/issue16452
Comment 7 GNOME Infrastructure Team 2018-01-10 19:57:35 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to GNOME's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/pygobject/issues/1.