| 167 | |
| 168 | class BoundNonDescriptorMethodWeakref(BoundMethodWeakref): |
| 169 | """A specialized BoundMethodWeakref, for platforms where instance methods |
| 170 | are not descriptors. |
| 171 | |
| 172 | It assumes that the function name and the target attribute name are the |
| 173 | same, instead of assuming that the function is a descriptor. This approach |
| 174 | is equally fast, but not 100% reliable because functions can be stored on an |
| 175 | attribute named differenty than the function's name such as in: |
| 176 | |
| 177 | class A: pass |
| 178 | def foo(self): return "foo" |
| 179 | A.bar = foo |
| 180 | |
| 181 | But this shouldn't be a common use case. So, on platforms where methods |
| 182 | aren't descriptors (such as Jython) this implementation has the advantage |
| 183 | of working in the most cases. |
| 184 | """ |
| 185 | def __init__(self, target, onDelete=None): |
| 186 | """Return a weak-reference-like instance for a bound method |
| 187 | |
| 188 | target -- the instance-method target for the weak |
| 189 | reference, must have im_self and im_func attributes |
| 190 | and be reconstructable via: |
| 191 | target.im_func.__get__( target.im_self ) |
| 192 | which is true of built-in instance methods. |
| 193 | onDelete -- optional callback which will be called |
| 194 | when this weak reference ceases to be valid |
| 195 | (i.e. either the object or the function is garbage |
| 196 | collected). Should take a single argument, |
| 197 | which will be passed a pointer to this object. |
| 198 | """ |
| 199 | assert getattr(target.im_self, target.__name__) == target, \ |
| 200 | ("method %s isn't available as the attribute %s of %s" % |
| 201 | (target, target.__name__, target.im_self)) |
| 202 | super(BoundNonDescriptorMethodWeakref, self).__init__(target, onDelete) |
| 203 | |
| 204 | def __call__(self): |
| 205 | """Return a strong reference to the bound method |
| 206 | |
| 207 | If the target cannot be retrieved, then will |
| 208 | return None, otherwise returns a bound instance |
| 209 | method for our object and function. |
| 210 | |
| 211 | Note: |
| 212 | You may call this method any number of times, |
| 213 | as it does not invalidate the reference. |
| 214 | """ |
| 215 | target = self.weakSelf() |
| 216 | if target is not None: |
| 217 | function = self.weakFunc() |
| 218 | if function is not None: |
| 219 | # Using curry() would be another option, but it erases the |
| 220 | # "signature" of the function. That is, after a function is |
| 221 | # curried, the inspect module can't be used to determine how |
| 222 | # many arguments the function expects, nor what keyword |
| 223 | # arguments it supports, and pydispatcher needs this |
| 224 | # information. |
| 225 | return getattr(target, function.__name__) |
| 226 | return None |
| 227 | |
| 228 | |
| 229 | def get_bound_method_weakref(target, onDelete): |
| 230 | """Instantiates the appropiate BoundMethodWeakRef, depending on the details of |
| 231 | the underlying class method implementation""" |
| 232 | if hasattr(target, '__get__'): |
| 233 | # target method is a descriptor, so the default implementation works: |
| 234 | return BoundMethodWeakref(target=target, onDelete=onDelete) |
| 235 | else: |
| 236 | # no luck, use the alternative implementation: |
| 237 | return BoundNonDescriptorMethodWeakref(target=target, onDelete=onDelete) |
| 238 | |