Slicer 4.2
Slicer is a multi-platform, free and open source software package for visualization and medical image computing
saferef.py
Go to the documentation of this file.
00001 ##############################################################################
00002 #
00003 #  Copyright (c) Django Software Foundation and individual contributors.
00004 #  All rights reserved.
00005 #
00006 #  Redistribution and use in source and binary forms, with or without modification,
00007 #  are permitted provided that the following conditions are met:
00008 #
00009 #    1. Redistributions of source code must retain the above copyright notice,
00010 #       this list of conditions and the following disclaimer.
00011 #
00012 #    2. Redistributions in binary form must reproduce the above copyright
00013 #       notice, this list of conditions and the following disclaimer in the
00014 #       documentation and/or other materials provided with the distribution.
00015 #
00016 #    3. Neither the name of Django nor the names of its contributors may be used
00017 #       to endorse or promote products derived from this software without
00018 #       specific prior written permission.
00019 #
00020 #  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00021 #  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00022 #  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00023 #  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
00024 #  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00025 #  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00026 #  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
00027 #  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00028 #  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00029 #  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00030 #
00031 ##############################################################################
00032 
00033 ##############################################################################
00034 # django.dispatch was originally forked from PyDispatcher.
00035 #
00036 # PyDispatcher License:
00037 #
00038 #  Copyright (c) 2001-2003, Patrick K. O'Brien and Contributors
00039 #  All rights reserved.
00040 #
00041 #  Redistribution and use in source and binary forms, with or without
00042 #  modification, are permitted provided that the following conditions
00043 #  are met:
00044 #
00045 #      Redistributions of source code must retain the above copyright
00046 #      notice, this list of conditions and the following disclaimer.
00047 #
00048 #      Redistributions in binary form must reproduce the above
00049 #      copyright notice, this list of conditions and the following
00050 #      disclaimer in the documentation and/or other materials
00051 #      provided with the distribution.
00052 #
00053 #      The name of Patrick K. O'Brien, or the name of any Contributor,
00054 #      may not be used to endorse or promote products derived from this
00055 #      software without specific prior written permission.
00056 #
00057 #  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00058 #  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00059 #  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00060 #  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00061 #  COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00062 #  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00063 #  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00064 #  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00065 #  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
00066 #  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00067 #  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
00068 #  OF THE POSSIBILITY OF SUCH DAMAGE.
00069 #
00070 ##############################################################################
00071 """
00072 "Safe weakrefs", originally from pyDispatcher.
00073 
00074 Provides a way to safely weakref any function, including bound methods (which
00075 aren't handled by the core weakref module).
00076 """
00077 
00078 import traceback
00079 import weakref
00080 
00081 def safeRef(target, onDelete = None):
00082     """Return a *safe* weak reference to a callable target
00083 
00084     target -- the object to be weakly referenced, if it's a
00085         bound method reference, will create a BoundMethodWeakref,
00086         otherwise creates a simple weakref.
00087     onDelete -- if provided, will have a hard reference stored
00088         to the callable to be called after the safe reference
00089         goes out of scope with the reference object, (either a
00090         weakref or a BoundMethodWeakref) as argument.
00091     """
00092     if hasattr(target, 'im_self'):
00093         if target.im_self is not None:
00094             # Turn a bound method into a BoundMethodWeakref instance.
00095             # Keep track of these instances for lookup by disconnect().
00096             assert hasattr(target, 'im_func'), """safeRef target %r has im_self, but no im_func, don't know how to create reference"""%( target,)
00097             reference = get_bound_method_weakref(
00098                 target=target,
00099                 onDelete=onDelete
00100             )
00101             return reference
00102     if callable(onDelete):
00103         return weakref.ref(target, onDelete)
00104     else:
00105         return weakref.ref( target )
00106 
00107 class BoundMethodWeakref(object):
00108     """'Safe' and reusable weak references to instance methods
00109 
00110     BoundMethodWeakref objects provide a mechanism for
00111     referencing a bound method without requiring that the
00112     method object itself (which is normally a transient
00113     object) is kept alive.  Instead, the BoundMethodWeakref
00114     object keeps weak references to both the object and the
00115     function which together define the instance method.
00116 
00117     Attributes:
00118         key -- the identity key for the reference, calculated
00119             by the class's calculateKey method applied to the
00120             target instance method
00121         deletionMethods -- sequence of callable objects taking
00122             single argument, a reference to this object which
00123             will be called when *either* the target object or
00124             target function is garbage collected (i.e. when
00125             this object becomes invalid).  These are specified
00126             as the onDelete parameters of safeRef calls.
00127         weakSelf -- weak reference to the target object
00128         weakFunc -- weak reference to the target function
00129 
00130     Class Attributes:
00131         _allInstances -- class attribute pointing to all live
00132             BoundMethodWeakref objects indexed by the class's
00133             calculateKey(target) method applied to the target
00134             objects.  This weak value dictionary is used to
00135             short-circuit creation so that multiple references
00136             to the same (object, function) pair produce the
00137             same BoundMethodWeakref instance.
00138 
00139     """
00140 
00141     _allInstances = weakref.WeakValueDictionary()
00142 
00143     def __new__( cls, target, onDelete=None, *arguments,**named ):
00144         """Create new instance or return current instance
00145 
00146         Basically this method of construction allows us to
00147         short-circuit creation of references to already-
00148         referenced instance methods.  The key corresponding
00149         to the target is calculated, and if there is already
00150         an existing reference, that is returned, with its
00151         deletionMethods attribute updated.  Otherwise the
00152         new instance is created and registered in the table
00153         of already-referenced methods.
00154         """
00155         key = cls.calculateKey(target)
00156         current =cls._allInstances.get(key)
00157         if current is not None:
00158             current.deletionMethods.append( onDelete)
00159             return current
00160         else:
00161             base = super( BoundMethodWeakref, cls).__new__( cls )
00162             cls._allInstances[key] = base
00163             base.__init__( target, onDelete, *arguments,**named)
00164             return base
00165 
00166     def __init__(self, target, onDelete=None):
00167         """Return a weak-reference-like instance for a bound method
00168 
00169         target -- the instance-method target for the weak
00170             reference, must have im_self and im_func attributes
00171             and be reconstructable via:
00172                 target.im_func.__get__( target.im_self )
00173             which is true of built-in instance methods.
00174         onDelete -- optional callback which will be called
00175             when this weak reference ceases to be valid
00176             (i.e. either the object or the function is garbage
00177             collected).  Should take a single argument,
00178             which will be passed a pointer to this object.
00179         """
00180         def remove(weak, self=self):
00181             """Set self.isDead to true when method or instance is destroyed"""
00182             methods = self.deletionMethods[:]
00183             del self.deletionMethods[:]
00184             try:
00185                 del self.__class__._allInstances[ self.key ]
00186             except KeyError:
00187                 pass
00188             for function in methods:
00189                 try:
00190                     if callable( function ):
00191                         function( self )
00192                 except Exception, e:
00193                     try:
00194                         traceback.print_exc()
00195                     except AttributeError, err:
00196                         print '''Exception during saferef %s cleanup function %s: %s'''%(
00197                             self, function, e
00198                         )
00199         self.deletionMethods = [onDelete]
00200         self.key = self.calculateKey( target )
00201         self.weakSelf = weakref.ref(target.im_self, remove)
00202         self.weakFunc = weakref.ref(target.im_func, remove)
00203         self.selfName = str(target.im_self)
00204         self.funcName = str(target.im_func.__name__)
00205 
00206     def calculateKey( cls, target ):
00207         """Calculate the reference key for this reference
00208 
00209         Currently this is a two-tuple of the id()'s of the
00210         target object and the target function respectively.
00211         """
00212         return (id(target.im_self),id(target.im_func))
00213     calculateKey = classmethod( calculateKey )
00214 
00215     def __str__(self):
00216         """Give a friendly representation of the object"""
00217         return """%s( %s.%s )"""%(
00218             self.__class__.__name__,
00219             self.selfName,
00220             self.funcName,
00221         )
00222 
00223     __repr__ = __str__
00224 
00225     def __nonzero__( self ):
00226         """Whether we are still a valid reference"""
00227         return self() is not None
00228 
00229     def __cmp__( self, other ):
00230         """Compare with another reference"""
00231         if not isinstance (other,self.__class__):
00232             return cmp( self.__class__, type(other) )
00233         return cmp( self.key, other.key)
00234 
00235     def __call__(self):
00236         """Return a strong reference to the bound method
00237 
00238         If the target cannot be retrieved, then will
00239         return None, otherwise returns a bound instance
00240         method for our object and function.
00241 
00242         Note:
00243             You may call this method any number of times,
00244             as it does not invalidate the reference.
00245         """
00246         target = self.weakSelf()
00247         if target is not None:
00248             function = self.weakFunc()
00249             if function is not None:
00250                 return function.__get__(target)
00251         return None
00252 
00253 class BoundNonDescriptorMethodWeakref(BoundMethodWeakref):
00254     """A specialized BoundMethodWeakref, for platforms where instance methods
00255     are not descriptors.
00256 
00257     It assumes that the function name and the target attribute name are the
00258     same, instead of assuming that the function is a descriptor. This approach
00259     is equally fast, but not 100% reliable because functions can be stored on an
00260     attribute named differenty than the function's name such as in:
00261 
00262     class A: pass
00263     def foo(self): return "foo"
00264     A.bar = foo
00265 
00266     But this shouldn't be a common use case. So, on platforms where methods
00267     aren't descriptors (such as Jython) this implementation has the advantage
00268     of working in the most cases.
00269     """
00270     def __init__(self, target, onDelete=None):
00271         """Return a weak-reference-like instance for a bound method
00272 
00273         target -- the instance-method target for the weak
00274             reference, must have im_self and im_func attributes
00275             and be reconstructable via:
00276                 target.im_func.__get__( target.im_self )
00277             which is true of built-in instance methods.
00278         onDelete -- optional callback which will be called
00279             when this weak reference ceases to be valid
00280             (i.e. either the object or the function is garbage
00281             collected).  Should take a single argument,
00282             which will be passed a pointer to this object.
00283         """
00284         assert getattr(target.im_self, target.__name__) == target, \
00285                ("method %s isn't available as the attribute %s of %s" %
00286                 (target, target.__name__, target.im_self))
00287         super(BoundNonDescriptorMethodWeakref, self).__init__(target, onDelete)
00288 
00289     def __call__(self):
00290         """Return a strong reference to the bound method
00291 
00292         If the target cannot be retrieved, then will
00293         return None, otherwise returns a bound instance
00294         method for our object and function.
00295 
00296         Note:
00297             You may call this method any number of times,
00298             as it does not invalidate the reference.
00299         """
00300         target = self.weakSelf()
00301         if target is not None:
00302             function = self.weakFunc()
00303             if function is not None:
00304                 # Using partial() would be another option, but it erases the
00305                 # "signature" of the function. That is, after a function is
00306                 # curried, the inspect module can't be used to determine how
00307                 # many arguments the function expects, nor what keyword
00308                 # arguments it supports, and pydispatcher needs this
00309                 # information.
00310                 return getattr(target, function.__name__)
00311         return None
00312 
00313 def get_bound_method_weakref(target, onDelete):
00314     """Instantiates the appropiate BoundMethodWeakRef, depending on the details of
00315     the underlying class method implementation"""
00316     if hasattr(target, '__get__'):
00317         # target method is a descriptor, so the default implementation works:
00318         return BoundMethodWeakref(target=target, onDelete=onDelete)
00319     else:
00320         # no luck, use the alternative implementation:
00321         return BoundNonDescriptorMethodWeakref(target=target, onDelete=onDelete)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines