|
|
|
@ -5,7 +5,9 @@ Provides a way to safely weakref any function, including bound methods (which
|
|
|
|
|
aren't handled by the core weakref module).
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
import weakref, traceback
|
|
|
|
|
import weakref
|
|
|
|
|
import traceback
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def safeRef(target, onDelete=None):
|
|
|
|
|
"""Return a *safe* weak reference to a callable target
|
|
|
|
@ -22,7 +24,9 @@ def safeRef(target, onDelete = None):
|
|
|
|
|
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,)
|
|
|
|
|
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
|
|
|
|
@ -33,6 +37,7 @@ def safeRef(target, onDelete = None):
|
|
|
|
|
else:
|
|
|
|
|
return weakref.ref(target)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class BoundMethodWeakref(object):
|
|
|
|
|
"""'Safe' and reusable weak references to instance methods
|
|
|
|
|
|
|
|
|
@ -122,9 +127,8 @@ class BoundMethodWeakref(object):
|
|
|
|
|
try:
|
|
|
|
|
traceback.print_exc()
|
|
|
|
|
except AttributeError:
|
|
|
|
|
print '''Exception during saferef %s cleanup function %s: %s'''%(
|
|
|
|
|
self, function, e
|
|
|
|
|
)
|
|
|
|
|
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)
|
|
|
|
@ -179,14 +183,15 @@ class BoundMethodWeakref(object):
|
|
|
|
|
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:
|
|
|
|
|
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"
|
|
|
|
@ -239,12 +244,14 @@ class BoundNonDescriptorMethodWeakref(BoundMethodWeakref):
|
|
|
|
|
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"""
|
|
|
|
|
"""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)
|
|
|
|
|
return BoundNonDescriptorMethodWeakref(target=target,
|
|
|
|
|
onDelete=onDelete)
|
|
|
|
|