| | 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 | |