@@ -361,9 +361,14 @@ class _BoundMethodProxy(object):
361361 Minor bugfixes by Michael Droettboom
362362 '''
363363 def __init__ (self , cb ):
364+ self ._hash = hash (cb )
365+ self ._destroy_callbacks = []
364366 try :
365367 try :
366- self .inst = ref (cb .im_self )
368+ if six .PY3 :
369+ self .inst = ref (cb .__self__ , self ._destroy )
370+ else :
371+ self .inst = ref (cb .im_self , self ._destroy )
367372 except TypeError :
368373 self .inst = None
369374 if six .PY3 :
@@ -377,6 +382,16 @@ def __init__(self, cb):
377382 self .func = cb
378383 self .klass = None
379384
385+ def add_destroy_callback (self , callback ):
386+ self ._destroy_callbacks .append (_BoundMethodProxy (callback ))
387+
388+ def _destroy (self , wk ):
389+ for callback in self ._destroy_callbacks :
390+ try :
391+ callback (self )
392+ except ReferenceError :
393+ pass
394+
380395 def __getstate__ (self ):
381396 d = self .__dict__ .copy ()
382397 # de-weak reference inst
@@ -433,6 +448,9 @@ def __ne__(self, other):
433448 '''
434449 return not self .__eq__ (other )
435450
451+ def __hash__ (self ):
452+ return self ._hash
453+
436454
437455class CallbackRegistry (object ):
438456 """
@@ -492,17 +510,32 @@ def connect(self, s, func):
492510 func will be called
493511 """
494512 self ._func_cid_map .setdefault (s , WeakKeyDictionary ())
495- if func in self ._func_cid_map [s ]:
496- return self ._func_cid_map [s ][func ]
513+ # Note proxy not needed in python 3.
514+ # TODO rewrite this when support for python2.x gets dropped.
515+ proxy = _BoundMethodProxy (func )
516+ if proxy in self ._func_cid_map [s ]:
517+ return self ._func_cid_map [s ][proxy ]
497518
519+ proxy .add_destroy_callback (self ._remove_proxy )
498520 self ._cid += 1
499521 cid = self ._cid
500- self ._func_cid_map [s ][func ] = cid
522+ self ._func_cid_map [s ][proxy ] = cid
501523 self .callbacks .setdefault (s , dict ())
502- proxy = _BoundMethodProxy (func )
503524 self .callbacks [s ][cid ] = proxy
504525 return cid
505526
527+ def _remove_proxy (self , proxy ):
528+ for signal , proxies in list (six .iteritems (self ._func_cid_map )):
529+ try :
530+ del self .callbacks [signal ][proxies [proxy ]]
531+ except KeyError :
532+ pass
533+
534+ if len (self .callbacks [signal ]) == 0 :
535+ del self .callbacks [signal ]
536+ del self ._func_cid_map [signal ]
537+
538+
506539 def disconnect (self , cid ):
507540 """
508541 disconnect the callback registered with callback id *cid*
@@ -513,7 +546,7 @@ def disconnect(self, cid):
513546 except KeyError :
514547 continue
515548 else :
516- for category , functions in list (
549+ for signal , functions in list (
517550 six .iteritems (self ._func_cid_map )):
518551 for function , value in list (six .iteritems (functions )):
519552 if value == cid :
@@ -527,11 +560,10 @@ def process(self, s, *args, **kwargs):
527560 """
528561 if s in self .callbacks :
529562 for cid , proxy in list (six .iteritems (self .callbacks [s ])):
530- # Clean out dead references
531- if proxy .inst is not None and proxy .inst () is None :
532- del self .callbacks [s ][cid ]
533- else :
563+ try :
534564 proxy (* args , ** kwargs )
565+ except ReferenceError :
566+ self ._remove_proxy (proxy )
535567
536568
537569class Scheduler (threading .Thread ):
0 commit comments