Django

Code

root/django/branches/gis/django/dispatch/saferef.py

Revision 8215, 10.1 kB (checked in by jbronn, 4 months ago)

gis: Merged revisions 7981-8001,8003-8011,8013-8033,8035-8036,8038-8039,8041-8063,8065-8076,8078-8139,8141-8154,8156-8214 via svnmerge from trunk.

  • Property svn:eol-style set to native
Line 
1 """Refactored "safe reference" from dispatcher.py"""
2 import weakref, traceback
3
4 def safeRef(target, onDelete = None):
5     """Return a *safe* weak reference to a callable target
6
7     target -- the object to be weakly referenced, if it's a
8         bound method reference, will create a BoundMethodWeakref,
9         otherwise creates a simple weakref.
10     onDelete -- if provided, will have a hard reference stored
11         to the callable to be called after the safe reference
12         goes out of scope with the reference object, (either a
13         weakref or a BoundMethodWeakref) as argument.
14     """
15     if hasattr(target, 'im_self'):
16         if target.im_self is not None:
17             # Turn a bound method into a BoundMethodWeakref instance.
18             # Keep track of these instances for lookup by disconnect().
19             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 = get_bound_method_weakref(
21                 target=target,
22                 onDelete=onDelete
23             )
24             return reference
25     if callable(onDelete):
26         return weakref.ref(target, onDelete)
27     else:
28         return weakref.ref( target )
29
30 class BoundMethodWeakref(object):
31     """'Safe' and reusable weak references to instance methods
32
33     BoundMethodWeakref objects provide a mechanism for
34     referencing a bound method without requiring that the
35     method object itself (which is normally a transient
36     object) is kept alive.  Instead, the BoundMethodWeakref
37     object keeps weak references to both the object and the
38     function which together define the instance method.
39
40     Attributes:
41         key -- the identity key for the reference, calculated
42             by the class's calculateKey method applied to the
43             target instance method
44         deletionMethods -- sequence of callable objects taking
45             single argument, a reference to this object which
46             will be called when *either* the target object or
47             target function is garbage collected (i.e. when
48             this object becomes invalid).  These are specified
49             as the onDelete parameters of safeRef calls.
50         weakSelf -- weak reference to the target object
51         weakFunc -- weak reference to the target function
52
53     Class Attributes:
54         _allInstances -- class attribute pointing to all live
55             BoundMethodWeakref objects indexed by the class's
56             calculateKey(target) method applied to the target
57             objects.  This weak value dictionary is used to
58             short-circuit creation so that multiple references
59             to the same (object, function) pair produce the
60             same BoundMethodWeakref instance.
61
62     """
63     _allInstances = weakref.WeakValueDictionary()
64     def __new__( cls, target, onDelete=None, *arguments,**named ):
65         """Create new instance or return current instance
66
67         Basically this method of construction allows us to
68         short-circuit creation of references to already-
69         referenced instance methods.  The key corresponding
70         to the target is calculated, and if there is already
71         an existing reference, that is returned, with its
72         deletionMethods attribute updated.  Otherwise the
73         new instance is created and registered in the table
74         of already-referenced methods.
75         """
76         key = cls.calculateKey(target)
77         current =cls._allInstances.get(key)
78         if current is not None:
79             current.deletionMethods.append( onDelete)
80             return current
81         else:
82             base = super( BoundMethodWeakref, cls).__new__( cls )
83             cls._allInstances[key] = base
84             base.__init__( target, onDelete, *arguments,**named)
85             return base
86     def __init__(self, target, onDelete=None):
87         """Return a weak-reference-like instance for a bound method
88
89         target -- the instance-method target for the weak
90             reference, must have im_self and im_func attributes
91             and be reconstructable via:
92                 target.im_func.__get__( target.im_self )
93             which is true of built-in instance methods.
94         onDelete -- optional callback which will be called
95             when this weak reference ceases to be valid
96             (i.e. either the object or the function is garbage
97             collected).  Should take a single argument,
98             which will be passed a pointer to this object.
99         """
100         def remove(weak, self=self):
101             """Set self.isDead to true when method or instance is destroyed"""
102             methods = self.deletionMethods[:]
103             del self.deletionMethods[:]
104             try:
105                 del self.__class__._allInstances[ self.key ]
106             except KeyError:
107                 pass
108             for function in methods:
109                 try:
110                     if callable( function ):
111                         function( self )
112                 except Exception, e:
113                     try:
114                         traceback.print_exc()
115                     except AttributeError, err:
116                         print '''Exception during saferef %s cleanup function %s: %s'''%(
117                             self, function, e
118                         )
119         self.deletionMethods = [onDelete]
120         self.key = self.calculateKey( target )
121         self.weakSelf = weakref.ref(target.im_self, remove)
122         self.weakFunc = weakref.ref(target.im_func, remove)
123         self.selfName = str(target.im_self)
124         self.funcName = str(target.im_func.__name__)
125     def calculateKey( cls, target ):
126         """Calculate the reference key for this reference
127
128         Currently this is a two-tuple of the id()'s of the
129         target object and the target function respectively.
130         """
131         return (id(target.im_self),id(target.im_func))
132     calculateKey = classmethod( calculateKey )
133     def __str__(self):
134         """Give a friendly representation of the object"""
135         return """%s( %s.%s )"""%(
136             self.__class__.__name__,
137             self.selfName,
138             self.funcName,
139         )
140     __repr__ = __str__
141     def __nonzero__( self ):
142         """Whether we are still a valid reference"""
143         return self() is not None
144     def __cmp__( self, other ):
145         """Compare with another reference"""
146         if not isinstance (other,self.__class__):
147             return cmp( self.__class__, type(other) )
148         return cmp( self.key, other.key)
149     def __call__(self):
150         """Return a strong reference to the bound method
151
152         If the target cannot be retrieved, then will
153         return None, otherwise returns a bound instance
154         method for our object and function.
155
156         Note:
157             You may call this method any number of times,
158             as it does not invalidate the reference.
159         """
160         target = self.weakSelf()
161         if target is not None:
162             function = self.weakFunc()
163             if function is not None:
164                 return function.__get__(target)
165         return None
166
167 class BoundNonDescriptorMethodWeakref(BoundMethodWeakref):
168     """A specialized BoundMethodWeakref, for platforms where instance methods
169     are not descriptors.
170
171     It assumes that the function name and the target attribute name are the
172     same, instead of assuming that the function is a descriptor. This approach
173     is equally fast, but not 100% reliable because functions can be stored on an
174     attribute named differenty than the function's name such as in:
175
176     class A: pass
177     def foo(self): return "foo"
178     A.bar = foo
179
180     But this shouldn't be a common use case. So, on platforms where methods
181     aren't descriptors (such as Jython) this implementation has the advantage
182     of working in the most cases.
183     """
184     def __init__(self, target, onDelete=None):
185         """Return a weak-reference-like instance for a bound method
186
187         target -- the instance-method target for the weak
188             reference, must have im_self and im_func attributes
189             and be reconstructable via:
190                 target.im_func.__get__( target.im_self )
191             which is true of built-in instance methods.
192         onDelete -- optional callback which will be called
193             when this weak reference ceases to be valid
194             (i.e. either the object or the function is garbage
195             collected).  Should take a single argument,
196             which will be passed a pointer to this object.
197         """
198         assert getattr(target.im_self, target.__name__) == target, \
199                ("method %s isn't available as the attribute %s of %s" %
200                 (target, target.__name__, target.im_self))
201         super(BoundNonDescriptorMethodWeakref, self).__init__(target, onDelete)
202
203     def __call__(self):
204         """Return a strong reference to the bound method
205
206         If the target cannot be retrieved, then will
207         return None, otherwise returns a bound instance
208         method for our object and function.
209
210         Note:
211             You may call this method any number of times,
212             as it does not invalidate the reference.
213         """
214         target = self.weakSelf()
215         if target is not None:
216             function = self.weakFunc()
217             if function is not None:
218                 # Using curry() would be another option, but it erases the
219                 # "signature" of the function. That is, after a function is
220                 # curried, the inspect module can't be used to determine how
221                 # many arguments the function expects, nor what keyword
222                 # arguments it supports, and pydispatcher needs this
223                 # information.
224                 return getattr(target, function.__name__)
225         return None
226
227
228 def get_bound_method_weakref(target, onDelete):
229     """Instantiates the appropiate BoundMethodWeakRef, depending on the details of
230     the underlying class method implementation"""
231     if hasattr(target, '__get__'):
232         # target method is a descriptor, so the default implementation works:
233         return BoundMethodWeakref(target=target, onDelete=onDelete)
234     else:
235         # no luck, use the alternative implementation:
236         return BoundNonDescriptorMethodWeakref(target=target, onDelete=onDelete)
Note: See TracBrowser for help on using the browser.