Django

Code

Changeset 6586

Show
Ignore:
Timestamp:
10/21/07 13:26:24 (1 year ago)
Author:
mtredinnick
Message:

Fixed #5664 -- Added a Jython workaround for some assumptions in the signal
dispatch code. Thanks, Leo Soto.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/dispatch/saferef.py

    r4265 r6586  
    11"""Refactored "safe reference" from dispatcher.py""" 
    22import weakref, traceback 
     3from django.utils.functional import curry 
    34 
    45def safeRef(target, onDelete = None): 
     
    1819            # Keep track of these instances for lookup by disconnect(). 
    1920            assert hasattr(target, 'im_func'), """safeRef target %r has im_self, but no im_func, don't know how to create reference"""%( target,) 
    20             reference = BoundMethodWeakref( 
     21            reference = get_bound_method_weakref( 
    2122                target=target, 
    2223                onDelete=onDelete 
     
    164165                return function.__get__(target) 
    165166        return None 
     167 
     168class 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 
     229def 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