| """ |
| "Safe weakrefs", originally from pyDispatcher. |
| |
| Provides a way to safely weakref any function, including bound methods (which |
| aren't handled by the core weakref module). |
| """ |
| |
| import weakref, traceback |
| |
| def safeRef(target, onDelete = None): |
| """Return a *safe* weak reference to a callable target |
| |
| target -- the object to be weakly referenced, if it's a |
| bound method reference, will create a BoundMethodWeakref, |
| otherwise creates a simple weakref. |
| onDelete -- if provided, will have a hard reference stored |
| to the callable to be called after the safe reference |
| goes out of scope with the reference object, (either a |
| weakref or a BoundMethodWeakref) as argument. |
| """ |
| if hasattr(target, 'im_self'): |
| if target.im_self is not None: |
| # Turn a bound method into a BoundMethodWeakref instance. |
| # 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,) |
| reference = get_bound_method_weakref( |
| target=target, |
| onDelete=onDelete |
| ) |
| return reference |
| if callable(onDelete): |
| return weakref.ref(target, onDelete) |
| else: |
| return weakref.ref( target ) |
| |
| class BoundMethodWeakref(object): |
| """'Safe' and reusable weak references to instance methods |
| |
| BoundMethodWeakref objects provide a mechanism for |
| referencing a bound method without requiring that the |
| method object itself (which is normally a transient |
| object) is kept alive. Instead, the BoundMethodWeakref |
| object keeps weak references to both the object and the |
| function which together define the instance method. |
| |
| Attributes: |
| key -- the identity key for the reference, calculated |
| by the class's calculateKey method applied to the |
| target instance method |
| deletionMethods -- sequence of callable objects taking |
| single argument, a reference to this object which |
| will be called when *either* the target object or |
| target function is garbage collected (i.e. when |
| this object becomes invalid). These are specified |
| as the onDelete parameters of safeRef calls. |
| weakSelf -- weak reference to the target object |
| weakFunc -- weak reference to the target function |
| |
| Class Attributes: |
| _allInstances -- class attribute pointing to all live |
| BoundMethodWeakref objects indexed by the class's |
| calculateKey(target) method applied to the target |
| objects. This weak value dictionary is used to |
| short-circuit creation so that multiple references |
| to the same (object, function) pair produce the |
| same BoundMethodWeakref instance. |
| |
| """ |
| |
| _allInstances = weakref.WeakValueDictionary() |
| |
| def __new__( cls, target, onDelete=None, *arguments,**named ): |
| """Create new instance or return current instance |
| |
| Basically this method of construction allows us to |
| short-circuit creation of references to already- |
| referenced instance methods. The key corresponding |
| to the target is calculated, and if there is already |
| an existing reference, that is returned, with its |
| deletionMethods attribute updated. Otherwise the |
| new instance is created and registered in the table |
| of already-referenced methods. |
| """ |
| key = cls.calculateKey(target) |
| current =cls._allInstances.get(key) |
| if current is not None: |
| current.deletionMethods.append( onDelete) |
| return current |
| else: |
| base = super( BoundMethodWeakref, cls).__new__( cls ) |
| cls._allInstances[key] = base |
| base.__init__( target, onDelete, *arguments,**named) |
| return base |
| |
| def __init__(self, target, onDelete=None): |
| """Return a weak-reference-like instance for a bound method |
| |
| target -- the instance-method target for the weak |
| reference, must have im_self and im_func attributes |
| and be reconstructable via: |
| target.im_func.__get__( target.im_self ) |
| which is true of built-in instance methods. |
| onDelete -- optional callback which will be called |
| when this weak reference ceases to be valid |
| (i.e. either the object or the function is garbage |
| collected). Should take a single argument, |
| which will be passed a pointer to this object. |
| """ |
| def remove(weak, self=self): |
| """Set self.isDead to true when method or instance is destroyed""" |
| methods = self.deletionMethods[:] |
| del self.deletionMethods[:] |
| try: |
| del self.__class__._allInstances[ self.key ] |
| except KeyError: |
| pass |
| for function in methods: |
| try: |
| if callable( function ): |
| function( self ) |
| except Exception, e: |
| try: |
| traceback.print_exc() |
| except AttributeError, err: |
| print '''Exception during saferef %s cleanup function %s: %s'''%( |
| self, function, e |
| ) |
| self.deletionMethods = [onDelete] |
| self.key = self.calculateKey( target ) |
| self.weakSelf = weakref.ref(target.im_self, remove) |
| self.weakFunc = weakref.ref(target.im_func, remove) |
| self.selfName = str(target.im_self) |
| self.funcName = str(target.im_func.__name__) |
| |
| def calculateKey( cls, target ): |
| """Calculate the reference key for this reference |
| |
| Currently this is a two-tuple of the id()'s of the |
| target object and the target function respectively. |
| """ |
| return (id(target.im_self),id(target.im_func)) |
| calculateKey = classmethod( calculateKey ) |
| |
| def __str__(self): |
| """Give a friendly representation of the object""" |
| return """%s( %s.%s )"""%( |
| self.__class__.__name__, |
| self.selfName, |
| self.funcName, |
| ) |
| |
| __repr__ = __str__ |
| |
| def __nonzero__( self ): |
| """Whether we are still a valid reference""" |
| return self() is not None |
| |
| def __cmp__( self, other ): |
| """Compare with another reference""" |
| if not isinstance (other,self.__class__): |
| return cmp( self.__class__, type(other) ) |
| return cmp( self.key, other.key) |
| |
| def __call__(self): |
| """Return a strong reference to the bound method |
| |
| If the target cannot be retrieved, then will |
| return None, otherwise returns a bound instance |
| method for our object and function. |
| |
| Note: |
| You may call this method any number of times, |
| as it does not invalidate the reference. |
| """ |
| target = self.weakSelf() |
| if target is not None: |
| function = self.weakFunc() |
| if function is not None: |
| return function.__get__(target) |
| return None |
| |
| class BoundNonDescriptorMethodWeakref(BoundMethodWeakref): |
| """A specialized BoundMethodWeakref, for platforms where instance methods |
| are not descriptors. |
| |
| 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 |
| is equally fast, but not 100% reliable because functions can be stored on an |
| attribute named differenty than the function's name such as in: |
| |
| class A: pass |
| def foo(self): return "foo" |
| A.bar = foo |
| |
| But this shouldn't be a common use case. So, on platforms where methods |
| aren't descriptors (such as Jython) this implementation has the advantage |
| of working in the most cases. |
| """ |
| def __init__(self, target, onDelete=None): |
| """Return a weak-reference-like instance for a bound method |
| |
| target -- the instance-method target for the weak |
| reference, must have im_self and im_func attributes |
| and be reconstructable via: |
| target.im_func.__get__( target.im_self ) |
| which is true of built-in instance methods. |
| onDelete -- optional callback which will be called |
| when this weak reference ceases to be valid |
| (i.e. either the object or the function is garbage |
| collected). Should take a single argument, |
| which will be passed a pointer to this object. |
| """ |
| assert getattr(target.im_self, target.__name__) == target, \ |
| ("method %s isn't available as the attribute %s of %s" % |
| (target, target.__name__, target.im_self)) |
| super(BoundNonDescriptorMethodWeakref, self).__init__(target, onDelete) |
| |
| def __call__(self): |
| """Return a strong reference to the bound method |
| |
| If the target cannot be retrieved, then will |
| return None, otherwise returns a bound instance |
| method for our object and function. |
| |
| Note: |
| You may call this method any number of times, |
| as it does not invalidate the reference. |
| """ |
| target = self.weakSelf() |
| if target is not None: |
| function = self.weakFunc() |
| if function is not None: |
| # Using curry() would be another option, but it erases the |
| # "signature" of the function. That is, after a function is |
| # curried, the inspect module can't be used to determine how |
| # many arguments the function expects, nor what keyword |
| # arguments it supports, and pydispatcher needs this |
| # information. |
| return getattr(target, function.__name__) |
| return None |
| |
| def get_bound_method_weakref(target, onDelete): |
| """Instantiates the appropiate BoundMethodWeakRef, depending on the details of |
| the underlying class method implementation""" |
| if hasattr(target, '__get__'): |
| # target method is a descriptor, so the default implementation works: |
| return BoundMethodWeakref(target=target, onDelete=onDelete) |
| else: |
| # no luck, use the alternative implementation: |
| return BoundNonDescriptorMethodWeakref(target=target, onDelete=onDelete) |