pep8'd sugar3.dispatch

master
William Orr 11 years ago committed by Daniel Narvaez
parent 220c9b68ef
commit 51f07bba81

@ -1,6 +1,7 @@
"""Multi-consumer multi-producer dispatching mechanism """Multi-consumer multi-producer dispatching mechanism
Originally based on pydispatch (BSD) http://pypi.python.org/pypi/PyDispatcher/2.0.1 Originally based on pydispatch (BSD)
http://pypi.python.org/pypi/PyDispatcher/2.0.1
See license.txt for original license. See license.txt for original license.
Heavily modified for Django's purposes. Heavily modified for Django's purposes.

@ -2,26 +2,29 @@ import weakref
try: try:
set set
except NameError: except NameError:
from sets import Set as set # Python 2.3 fallback from sets import Set as set # Python 2.3 fallback
from sugar3.dispatch import saferef from sugar3.dispatch import saferef
WEAKREF_TYPES = (weakref.ReferenceType, saferef.BoundMethodWeakref) WEAKREF_TYPES = (weakref.ReferenceType, saferef.BoundMethodWeakref)
def _make_id(target): def _make_id(target):
if hasattr(target, 'im_func'): if hasattr(target, 'im_func'):
return (id(target.im_self), id(target.im_func)) return (id(target.im_self), id(target.im_func))
return id(target) return id(target)
class Signal(object): class Signal(object):
"""Base class for all signals """Base class for all signals
Internal attributes: Internal attributes:
receivers -- { receriverkey (id) : weakref(receiver) } receivers -- { receriverkey (id) : weakref(receiver) }
""" """
def __init__(self, providing_args=None): def __init__(self, providing_args=None):
"""providing_args -- A list of the arguments this signal can pass along in """providing_args -- A list of the arguments
this signal can pass along in
a send() call. a send() call.
""" """
self.receivers = [] self.receivers = []
@ -31,7 +34,7 @@ class Signal(object):
def connect(self, receiver, sender=None, weak=True, dispatch_uid=None): def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
"""Connect receiver to sender for signal """Connect receiver to sender for signal
receiver -- a function or an instance method which is to receiver -- a function or an instance method which is to
receive signals. Receivers must be receive signals. Receivers must be
hashable objects. hashable objects.
@ -39,7 +42,7 @@ class Signal(object):
if weak is True, then receiver must be weak-referencable if weak is True, then receiver must be weak-referencable
(more precisely saferef.safeRef() must be able to create (more precisely saferef.safeRef() must be able to create
a reference to the receiver). a reference to the receiver).
Receivers must be able to accept keyword arguments. Receivers must be able to accept keyword arguments.
If receivers have a dispatch_uid attribute, the receiver will If receivers have a dispatch_uid attribute, the receiver will
@ -54,20 +57,21 @@ class Signal(object):
By default, the module will attempt to use weak By default, the module will attempt to use weak
references to the receiver objects. If this parameter references to the receiver objects. If this parameter
is false, then strong references will be used. is false, then strong references will be used.
dispatch_uid -- an identifier used to uniquely identify a particular dispatch_uid -- an identifier used to uniquely identify a particular
instance of a receiver. This will usually be a string, though it instance of a receiver. This will usually be a string, though it
may be anything hashable. may be anything hashable.
returns None returns None
""" """
if dispatch_uid: if dispatch_uid:
lookup_key = (dispatch_uid, _make_id(sender)) lookup_key = (dispatch_uid, _make_id(sender))
else: else:
lookup_key = (_make_id(receiver), _make_id(sender)) lookup_key = (_make_id(receiver), _make_id(sender))
if weak: if weak:
receiver = saferef.safeRef(receiver, onDelete=self._remove_receiver) receiver = saferef.safeRef(
receiver, onDelete=self._remove_receiver)
for r_key, _ in self.receivers: for r_key, _ in self.receivers:
if r_key == lookup_key: if r_key == lookup_key:
@ -75,15 +79,16 @@ class Signal(object):
else: else:
self.receivers.append((lookup_key, receiver)) self.receivers.append((lookup_key, receiver))
def disconnect(self, receiver=None, sender=None, weak=True, dispatch_uid=None): def disconnect(self, receiver=None, sender=None, weak=True,
dispatch_uid=None):
"""Disconnect receiver from sender for signal """Disconnect receiver from sender for signal
receiver -- the registered receiver to disconnect. May be none if receiver -- the registered receiver to disconnect. May be none if
dispatch_uid is specified. dispatch_uid is specified.
sender -- the registered sender to disconnect sender -- the registered sender to disconnect
weak -- the weakref state to disconnect weak -- the weakref state to disconnect
dispatch_uid -- the unique identifier of the receiver to disconnect dispatch_uid -- the unique identifier of the receiver to disconnect
disconnect reverses the process of connect. disconnect reverses the process of connect.
If weak references are used, disconnect need not be called. If weak references are used, disconnect need not be called.
@ -106,7 +111,7 @@ class Signal(object):
sender -- the sender of the signal sender -- the sender of the signal
Either a specific object or None. Either a specific object or None.
named -- named arguments which will be passed to receivers. named -- named arguments which will be passed to receivers.
Returns a list of tuple pairs [(receiver, response), ... ]. Returns a list of tuple pairs [(receiver, response), ... ].
@ -140,7 +145,8 @@ class Signal(object):
Return a list of tuple pairs [(receiver, response), ... ], Return a list of tuple pairs [(receiver, response), ... ],
may raise DispatcherKeyError may raise DispatcherKeyError
if any receiver raises an error (specifically any subclass of Exception), if any receiver raises an error (specifically any subclass of
Exception),
the error instance is returned as the result for that receiver. the error instance is returned as the result for that receiver.
""" """

@ -5,9 +5,11 @@ Provides a way to safely weakref any function, including bound methods (which
aren't handled by the core weakref module). aren't handled by the core weakref module).
""" """
import weakref, traceback import weakref
import traceback
def safeRef(target, onDelete = None):
def safeRef(target, onDelete=None):
"""Return a *safe* weak reference to a callable target """Return a *safe* weak reference to a callable target
target -- the object to be weakly referenced, if it's a target -- the object to be weakly referenced, if it's a
@ -22,7 +24,9 @@ def safeRef(target, onDelete = None):
if target.im_self is not None: if target.im_self is not None:
# Turn a bound method into a BoundMethodWeakref instance. # Turn a bound method into a BoundMethodWeakref instance.
# Keep track of these instances for lookup by disconnect(). # Keep track of these instances for lookup by disconnect().
assert hasattr(target, 'im_func'), """safeRef target %r has im_self, but no im_func, don't know how to create reference"""%( target,) assert hasattr(target, 'im_func'), \
"safeRef target %r has im_self, but no im_func, " \
"don't know how to create reference" % (target,)
reference = get_bound_method_weakref( reference = get_bound_method_weakref(
target=target, target=target,
onDelete=onDelete onDelete=onDelete
@ -31,7 +35,8 @@ def safeRef(target, onDelete = None):
if callable(onDelete): if callable(onDelete):
return weakref.ref(target, onDelete) return weakref.ref(target, onDelete)
else: else:
return weakref.ref( target ) return weakref.ref(target)
class BoundMethodWeakref(object): class BoundMethodWeakref(object):
"""'Safe' and reusable weak references to instance methods """'Safe' and reusable weak references to instance methods
@ -66,10 +71,10 @@ class BoundMethodWeakref(object):
same BoundMethodWeakref instance. same BoundMethodWeakref instance.
""" """
_allInstances = weakref.WeakValueDictionary() _allInstances = weakref.WeakValueDictionary()
def __new__( cls, target, onDelete=None, *arguments,**named ): def __new__(cls, target, onDelete=None, *arguments, **named):
"""Create new instance or return current instance """Create new instance or return current instance
Basically this method of construction allows us to Basically this method of construction allows us to
@ -82,16 +87,16 @@ class BoundMethodWeakref(object):
of already-referenced methods. of already-referenced methods.
""" """
key = cls.calculateKey(target) key = cls.calculateKey(target)
current =cls._allInstances.get(key) current = cls._allInstances.get(key)
if current is not None: if current is not None:
current.deletionMethods.append( onDelete) current.deletionMethods.append(onDelete)
return current return current
else: else:
base = super( BoundMethodWeakref, cls).__new__( cls ) base = super(BoundMethodWeakref, cls).__new__(cls)
cls._allInstances[key] = base cls._allInstances[key] = base
base.__init__( target, onDelete, *arguments,**named) base.__init__(target, onDelete, *arguments, **named)
return base return base
def __init__(self, target, onDelete=None): def __init__(self, target, onDelete=None):
"""Return a weak-reference-like instance for a bound method """Return a weak-reference-like instance for a bound method
@ -111,56 +116,55 @@ class BoundMethodWeakref(object):
methods = self.deletionMethods[:] methods = self.deletionMethods[:]
del self.deletionMethods[:] del self.deletionMethods[:]
try: try:
del self.__class__._allInstances[ self.key ] del self.__class__._allInstances[self.key]
except KeyError: except KeyError:
pass pass
for function in methods: for function in methods:
try: try:
if callable( function ): if callable(function):
function( self ) function(self)
except Exception, e: except Exception, e:
try: try:
traceback.print_exc() traceback.print_exc()
except AttributeError: except AttributeError:
print '''Exception during saferef %s cleanup function %s: %s'''%( print "Exception during saferef %s cleanup "
self, function, e "function %s: %s" % (self, function, e)
)
self.deletionMethods = [onDelete] self.deletionMethods = [onDelete]
self.key = self.calculateKey( target ) self.key = self.calculateKey(target)
self.weakSelf = weakref.ref(target.im_self, remove) self.weakSelf = weakref.ref(target.im_self, remove)
self.weakFunc = weakref.ref(target.im_func, remove) self.weakFunc = weakref.ref(target.im_func, remove)
self.selfName = str(target.im_self) self.selfName = str(target.im_self)
self.funcName = str(target.im_func.__name__) self.funcName = str(target.im_func.__name__)
def calculateKey( cls, target ): def calculateKey(cls, target):
"""Calculate the reference key for this reference """Calculate the reference key for this reference
Currently this is a two-tuple of the id()'s of the Currently this is a two-tuple of the id()'s of the
target object and the target function respectively. target object and the target function respectively.
""" """
return (id(target.im_self),id(target.im_func)) return (id(target.im_self), id(target.im_func))
calculateKey = classmethod( calculateKey ) calculateKey = classmethod(calculateKey)
def __str__(self): def __str__(self):
"""Give a friendly representation of the object""" """Give a friendly representation of the object"""
return """%s( %s.%s )"""%( return """%s( %s.%s )""" % (
self.__class__.__name__, self.__class__.__name__,
self.selfName, self.selfName,
self.funcName, self.funcName,
) )
__repr__ = __str__ __repr__ = __str__
def __nonzero__( self ): def __nonzero__(self):
"""Whether we are still a valid reference""" """Whether we are still a valid reference"""
return self() is not None return self() is not None
def __cmp__( self, other ): def __cmp__(self, other):
"""Compare with another reference""" """Compare with another reference"""
if not isinstance (other,self.__class__): if not isinstance(other, self.__class__):
return cmp( self.__class__, type(other) ) return cmp(self.__class__, type(other))
return cmp( self.key, other.key) return cmp(self.key, other.key)
def __call__(self): def __call__(self):
"""Return a strong reference to the bound method """Return a strong reference to the bound method
@ -179,14 +183,15 @@ class BoundMethodWeakref(object):
return function.__get__(target) return function.__get__(target)
return None return None
class BoundNonDescriptorMethodWeakref(BoundMethodWeakref): class BoundNonDescriptorMethodWeakref(BoundMethodWeakref):
"""A specialized BoundMethodWeakref, for platforms where instance methods """A specialized BoundMethodWeakref, for platforms where instance methods
are not descriptors. are not descriptors.
It assumes that the function name and the target attribute name are the It assumes that the function name and the target attribute name are the
same, instead of assuming that the function is a descriptor. This approach same, instead of assuming that the function is a descriptor. This approach
is equally fast, but not 100% reliable because functions can be stored on an is equally fast, but not 100% reliable because functions can be stored on
attribute named differenty than the function's name such as in: an attribute named differenty than the function's name such as in:
class A: pass class A: pass
def foo(self): return "foo" def foo(self): return "foo"
@ -211,7 +216,7 @@ class BoundNonDescriptorMethodWeakref(BoundMethodWeakref):
which will be passed a pointer to this object. which will be passed a pointer to this object.
""" """
assert getattr(target.im_self, target.__name__) == target, \ assert getattr(target.im_self, target.__name__) == target, \
("method %s isn't available as the attribute %s of %s" % ("method %s isn't available as the attribute %s of %s" %
(target, target.__name__, target.im_self)) (target, target.__name__, target.im_self))
super(BoundNonDescriptorMethodWeakref, self).__init__(target, onDelete) super(BoundNonDescriptorMethodWeakref, self).__init__(target, onDelete)
@ -239,12 +244,14 @@ class BoundNonDescriptorMethodWeakref(BoundMethodWeakref):
return getattr(target, function.__name__) return getattr(target, function.__name__)
return None return None
def get_bound_method_weakref(target, onDelete): def get_bound_method_weakref(target, onDelete):
"""Instantiates the appropiate BoundMethodWeakRef, depending on the details of """Instantiates the appropiate BoundMethodWeakRef, depending on the
the underlying class method implementation""" details of the underlying class method implementation"""
if hasattr(target, '__get__'): if hasattr(target, '__get__'):
# target method is a descriptor, so the default implementation works: # target method is a descriptor, so the default implementation works:
return BoundMethodWeakref(target=target, onDelete=onDelete) return BoundMethodWeakref(target=target, onDelete=onDelete)
else: else:
# no luck, use the alternative implementation: # no luck, use the alternative implementation:
return BoundNonDescriptorMethodWeakref(target=target, onDelete=onDelete) return BoundNonDescriptorMethodWeakref(target=target,
onDelete=onDelete)

Loading…
Cancel
Save