Author: tack
Date: Mon Jan 22 21:00:24 2007
New Revision: 2437
Modified:
trunk/base/src/notifier/callback.py
trunk/base/test/callbacks.py
Log:
Rework Signal class to use Callback and WeakCallback objects: when a
callback is connected, a Callback object will be returned; fixed bug
where doing cb == Callback(cb) wouldn't be True; simplified WeakCallback
a bit (removed __call__ and created get_user_args() method); added
__nonzero__ method that always returns True for Signal objects
Modified: trunk/base/src/notifier/callback.py
==============================================================================
--- trunk/base/src/notifier/callback.py (original)
+++ trunk/base/src/notifier/callback.py Mon Jan 22 21:00:24 2007
@@ -130,18 +130,25 @@
def set_user_args_first(self, flag = True):
self._user_args_first = flag
+
+ def get_user_args(self):
+ return self._args, self._kwargs
+
+
def _get_callback(self):
return self._callback
+
def _merge_args(self, args, kwargs):
+ user_args, user_kwargs = self.get_user_args()
if self._ignore_caller_args:
- cb_args, cb_kwargs = self._args, self._kwargs
+ cb_args, cb_kwargs = user_args, user_kwargs
else:
if self._user_args_first:
- cb_args, cb_kwargs = self._args + args, kwargs
- cb_kwargs.update(self._kwargs)
+ cb_args, cb_kwargs = user_args + args, kwargs
+ cb_kwargs.update(user_kwargs)
else:
- cb_args, cb_kwargs = args + self._args, self._kwargs
+ cb_args, cb_kwargs = args + user_args, user_kwargs
cb_kwargs.update(kwargs)
return cb_args, cb_kwargs
@@ -176,11 +183,11 @@
"""
return None
- def __cmp__(self, func):
+ def __eq__(self, func):
"""
Compares the given function with the callback function we're wrapping.
"""
- return cmp(id(self), id(func)) or cmp(self._get_callback(), func)
+ return id(self) == id(func) or self._get_callback() == func
class NotifierCallback(Callback):
@@ -244,8 +251,10 @@
self._instance = _weakref.ref(callback.im_self,
self._weakref_destroyed)
self._callback = callback.im_func.func_name
else:
- # No need to weakref functions. (If we do, we can't use closures.)
self._instance = None
+ # Don't weakref lambdas.
+ if not hasattr(callback, 'func_name') or callback.func_name !=
'<lambda>':
+ self._callback = _weakref.ref(callback,
self._weakref_destroyed)
self._args = weakref_data(args, self._weakref_destroyed)
self._kwargs = weakref_data(kwargs, self._weakref_destroyed)
@@ -263,26 +272,20 @@
if self._instance:
if self._instance() != None:
return getattr(self._instance(), self._callback)
+ elif isinstance(self._callback, _weakref.ReferenceType):
+ return self._callback()
else:
return self._callback
+ def get_user_args(self):
+ return unweakref_data(self._args), unweakref_data(self._kwargs)
def __call__(self, *args, **kwargs):
if _python_shutting_down != False:
# Shutdown
return False
- save_args, save_kwargs = self._args, self._kwargs
-
- # Remove weakrefs from user data before invoking the callback.
- self._args = unweakref_data(self._args)
- self._kwargs = unweakref_data(self._kwargs)
-
- result = super(WeakCallback, self).__call__(*args, **kwargs)
-
- self._args, self._kwargs = save_args, save_kwargs
-
- return result
+ return super(WeakCallback, self).__call__(*args, **kwargs)
def set_weakref_destroyed_cb(self, callback):
@@ -322,32 +325,37 @@
def __iter__(self):
for cb in self._callbacks:
- cb_callback, cb_args, cb_kwargs, cb_once, cb_weak = cb
- if cb_weak:
- cb_callback = cb_callback._get_callback()
-
- yield cb_callback
+ yield cb
def __len__(self):
return len(self._callbacks)
+ def __nonzero__(self):
+ return True
+
+
def __contains__(self, key):
if not callable(key):
return False
for cb in self._callbacks:
- cb_callback, cb_args, cb_kwargs, cb_once, cb_weak = cb
- if cb_weak:
- cb_callback = cb_callback._get_callback()
- if cb_callback == key:
+ if cb == key:
return True
return False
- def _connect(self, callback, args = (), kwargs = {}, once = False,
- weak = False, pos = -1):
+ def _connect(self, callback, args = (), kwargs = {}, once = False, weak =
False, pos = -1):
+ """
+ Connects a new callback to the signal. args and kwargs will be bound
+ to the callback and merged with the args and kwargs passed during
+ emit(). If weak is True, a WeakCallback will be created. If once is
+ True, the callback will be automatically disconnected after the next
+ emit().
+
+ This method returns the Callback (or WeakCallback) object created.
+ """
assert(callable(callback))
@@ -359,26 +367,23 @@
raise Exception("Signal callbacks exceeds 40")
if weak:
- callback = WeakCallback(callback)
-
+ callback = WeakCallback(callback, *args, **kwargs)
# We create a callback for weakref destruction for both the
- # signal callback as well as signal data. The destroy callback
- # has the signal callback passed as the first parameter (because
- # set_user_args_first() is called), and WeakCallback will pass
- # the weakref object itself as the second parameter.
+ # signal callback as well as signal data.
destroy_cb = Callback(self._weakref_destroyed, callback)
- destroy_cb.set_user_args_first()
callback.set_weakref_destroyed_cb(destroy_cb)
+ else:
+ callback = Callback(callback, *args, **kwargs)
+
+ callback._signal_once = once
- args = weakref_data(args, destroy_cb)
- kwargs = weakref_data(kwargs, destroy_cb)
if pos == -1:
pos = len(self._callbacks)
- self._callbacks.insert(pos, (callback, args, kwargs, once, weak))
+ self._callbacks.insert(pos, callback)
if self._changed_cb:
self._changed_cb(self, Signal.SIGNAL_CONNECTED)
- return True
+ return callback
def connect(self, callback, *args, **kwargs):
@@ -403,26 +408,15 @@
assert(callable(callback))
new_callbacks = []
for cb in self._callbacks[:]:
- cb_callback, cb_args, cb_kwargs, cb_once, cb_weak = cb
- if cb_weak:
- cb_callback_u = cb_callback._get_callback()
- cb_args_u, cb_kwargs_u = unweakref_data((cb_args, cb_kwargs))
- else:
- cb_callback_u = cb_args_u = cb_kwargs_u = None
-
- if (callback in (cb_callback, cb_callback_u) and len(args) == 0)
or \
- (cb_callback, cb_args, cb_kwargs) == (callback, args, kwargs)
or \
- (cb_callback_u, cb_args_u, cb_kwargs_u) == (callback, args,
kwargs):
+ if cb == callback and (len(args) == len(kwargs) == 0 or (args,
kwargs) == cb.get_user_args()):
# This matches what we want to disconnect.
continue
-
new_callbacks.append(cb)
if len(new_callbacks) != len(self._callbacks):
self._callbacks = new_callbacks
if self._changed_cb:
self._changed_cb(self, Signal.SIGNAL_DISCONNECTED)
-
return True
return False
@@ -438,6 +432,7 @@
if self._changed_cb and count > 0:
self._changed_cb(self, Signal.SIGNAL_DISCONNECTED)
+
def emit(self, *args, **kwargs):
"""
Emits the signal, passing the args and kwargs to each signal handler.
@@ -448,26 +443,12 @@
return True
retval = True
- for cb_callback, cb_args, cb_kwargs, cb_once, cb_weak in
self._callbacks[:]:
- if cb_weak:
- cb_callback_u = cb_callback._get_callback()
- if cb_callback_u == None:
- # A reference died while we were in the process of
- # emitting this signal. This callback should already be
- # disconnected, but since we're working on a copy we will
- # encounter it.
- continue
-
- cb_callback = cb_callback_u
- cb_args, cb_kwargs = unweakref_data((cb_args, cb_kwargs))
- else:
- cb_kwargs = cb_kwargs.copy()
+ for cb in self._callbacks[:]:
+ if cb._signal_once:
+ self.disconnect(cb)
- if cb_once:
- self.disconnect(cb_callback, *cb_args, **cb_kwargs)
- cb_kwargs.update(kwargs)
try:
- if cb_callback(*(args + cb_args), **cb_kwargs) == False:
+ if cb(*args, **kwargs) == False:
retval = False
except (KeyboardInterrupt, SystemExit):
raise SystemExit
@@ -476,10 +457,9 @@
return retval
- def _weakref_destroyed(self, callback, weakref):
+ def _weakref_destroyed(self, weakref, callback):
if _python_shutting_down == False:
- self._disconnect(callback, (), None)
-
+ self._disconnect(callback, (), {})
def count(self):
return len(self._callbacks)
Modified: trunk/base/test/callbacks.py
==============================================================================
--- trunk/base/test/callbacks.py (original)
+++ trunk/base/test/callbacks.py Mon Jan 22 21:00:24 2007
@@ -53,9 +53,14 @@
cb = WeakCallback(cb_func)
test( cb(42), ((42,), {}) )
+# Lambdas are not weakref'd
+cb = WeakCallback(lambda arg: arg)
+test( cb(42), 42)
+
+# Functions are weakref'd
cb = WeakCallback(cb_func2)
del cb_func2
-test( cb(42), ((42,), {}) )
+test( cb(42), None )
cb_meth = Cls().meth
cb = WeakCallback(cb_meth)
@@ -170,7 +175,6 @@
test(sig.count(), 1)
del cb
-# XXX: with the new code this will fail until emit() is called.
test(sig.count(), 0)
sig.emit()
test(sig.count(), 0)
@@ -179,7 +183,6 @@
sig.emit()
test(result, [])
-# XXX: with the new code this will fail until emit() is called.
cb = Cls().meth
sig.connect_weak(cb, Cls())
test(sig.count(), 0)
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Freevo-cvslog mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/freevo-cvslog