Main Page | Packages | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | Related Pages

saferef.py

00001 """Refactored "safe reference" from dispatcher.py"""
00002 
00003 __version__  = "$Revision: 2.1 $"
00004 
00005 import weakref, traceback
00006 
00007 def safeRef(target, onDelete = None):
00008     """Return a *safe* weak reference to a callable target
00009 
00010     target -- the object to be weakly referenced, if it's a
00011         bound method reference, will create a BoundMethodWeakref,
00012         otherwise creates a simple weakref.
00013     onDelete -- if provided, will have a hard reference stored
00014         to the callable to be called after the safe reference
00015         goes out of scope with the reference object, (either a
00016         weakref or a BoundMethodWeakref) as argument.
00017     """
00018     if hasattr(target, 'im_self'):
00019         if target.im_self is not None:
00020             # Turn a bound method into a BoundMethodWeakref instance.
00021             # Keep track of these instances for lookup by disconnect().
00022             assert hasattr(target, 'im_func'), """safeRef target %r has im_self, but no im_func, don't know how to create reference"""%( target,)
00023             reference = BoundMethodWeakref(
00024                 target=target,
00025                 onDelete=onDelete
00026             )
00027             return reference
00028     if callable(onDelete):
00029         return weakref.ref(target, onDelete)
00030     else:
00031         return weakref.ref( target )
00032 
00033 class BoundMethodWeakref(object):
00034     """'Safe' and reusable weak references to instance methods
00035 
00036     BoundMethodWeakref objects provide a mechanism for
00037     referencing a bound method without requiring that the
00038     method object itself (which is normally a transient
00039     object) is kept alive.  Instead, the BoundMethodWeakref
00040     object keeps weak references to both the object and the
00041     function which together define the instance method.
00042 
00043     Attributes:
00044         key -- the identity key for the reference, calculated
00045             by the class's calculateKey method applied to the
00046             target instance method
00047         deletionMethods -- sequence of callable objects taking
00048             single argument, a reference to this object which
00049             will be called when *either* the target object or
00050             target function is garbage collected (i.e. when
00051             this object becomes invalid).  These are specified
00052             as the onDelete parameters of safeRef calls.
00053         weakSelf -- weak reference to the target object
00054         weakFunc -- weak reference to the target function
00055 
00056     Class Attributes:
00057         _allInstances -- class attribute pointing to all live
00058             BoundMethodWeakref objects indexed by the class's
00059             calculateKey(target) method applied to the target
00060             objects.  This weak value dictionary is used to
00061             short-circuit creation so that multiple references
00062             to the same (object, function) pair produce the
00063             same BoundMethodWeakref instance.
00064         
00065     """
00066     _allInstances = weakref.WeakValueDictionary()
00067     def __new__( cls, target, onDelete=None, *arguments,**named ):
00068         """Create new instance or return current instance
00069 
00070         Basically this method of construction allows us to
00071         short-circuit creation of references to already-
00072         referenced instance methods.  The key corresponding
00073         to the target is calculated, and if there is already
00074         an existing reference, that is returned, with its
00075         deletionMethods attribute updated.  Otherwise the
00076         new instance is created and registered in the table
00077         of already-referenced methods.
00078         """
00079         key = cls.calculateKey(target)
00080         current =cls._allInstances.get(key)
00081         if current is not None:
00082             current.deletionMethods.append( onDelete)
00083             return current
00084         else:
00085             base = super( BoundMethodWeakref, cls).__new__( cls )
00086             cls._allInstances[key] = base
00087             base.__init__( target, onDelete, *arguments,**named)
00088             return base
00089     def __init__(self, target, onDelete=None):
00090         """Return a weak-reference-like instance for a bound method
00091 
00092         target -- the instance-method target for the weak
00093             reference, must have im_self and im_func attributes
00094             and be reconstructable via:
00095                 target.im_func.__get__( target.im_self )
00096             which is true of built-in instance methods.
00097         onDelete -- optional callback which will be called
00098             when this weak reference ceases to be valid
00099             (i.e. either the object or the function is garbage
00100             collected).  Should take a single argument,
00101             which will be passed a pointer to this object.
00102         """
00103         def remove(weak, self=self):
00104             """Set self.isDead to true when method or instance is destroyed"""
00105             methods = self.deletionMethods[:]
00106             del self.deletionMethods[:]
00107             try:
00108                 del self.__class__._allInstances[ self.key ]
00109             except KeyError:
00110                 pass
00111             for function in methods:
00112                 try:
00113                     if callable( function ):
00114                         function( self )
00115                 except Exception:
00116                     traceback.print_exc()
00117         self.deletionMethods = [onDelete]
00118         self.key = self.calculateKey( target )
00119         self.weakSelf = weakref.ref(target.im_self, remove)
00120         self.weakFunc = weakref.ref(target.im_func, remove)
00121     def calculateKey( cls, target ):
00122         """Calculate the reference key for this reference
00123 
00124         Currently this is a two-tuple of the id()'s of the
00125         target object and the target function respectively.
00126         """
00127         return (id(target.im_self),id(target.im_func))
00128     calculateKey = classmethod( calculateKey )
00129     def __str__(self):
00130         """Give a friendly representation of the object"""
00131         return """%s( %s.%s )"""%(
00132             self.__class__.__name__,
00133             self.weakSelf(),
00134             self.weakFunc().__name__,
00135         )
00136     __repr__ = __str__
00137     def __nonzero__( self ):
00138         """Whether we are still a valid reference"""
00139         return self() is not None
00140     def __cmp__( self, other ):
00141         """Compare with another reference"""
00142         if not isinstance (other,self.__class__):
00143             return cmp( self.__class__, type(other) )
00144         return cmp( self.key, other.key)
00145     def __call__(self):
00146         """Return a strong reference to the bound method
00147 
00148         If the target cannot be retrieved, then will
00149         return None, otherwise returns a bound instance
00150         method for our object and function.
00151 
00152         Note:
00153             You may call this method any number of times,
00154             as it does not invalidate the reference.
00155         """
00156         target = self.weakSelf()
00157         if target is not None:
00158             function = self.weakFunc()
00159             if function is not None:
00160                 return function.__get__(target)
00161         return None

Generated on Fri Jul 21 13:26:32 2006 for LATTE R04-12-00 by doxygen 1.4.3