Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/blinker/_saferef.py: 27%

83 statements  

« prev     ^ index     » next       coverage.py v7.0.1, created at 2022-12-25 06:11 +0000

1# extracted from Louie, http://pylouie.org/ 

2# updated for Python 3 

3# 

4# Copyright (c) 2006 Patrick K. O'Brien, Mike C. Fletcher, 

5# Matthew R. Scott 

6# 

7# Redistribution and use in source and binary forms, with or without 

8# modification, are permitted provided that the following conditions are 

9# met: 

10# 

11# * Redistributions of source code must retain the above copyright 

12# notice, this list of conditions and the following disclaimer. 

13# 

14# * Redistributions in binary form must reproduce the above 

15# copyright notice, this list of conditions and the following 

16# disclaimer in the documentation and/or other materials provided 

17# with the distribution. 

18# 

19# * Neither the name of the <ORGANIZATION> nor the names of its 

20# contributors may be used to endorse or promote products derived 

21# from this software without specific prior written permission. 

22# 

23# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 

24# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 

25# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 

26# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 

27# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 

28# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 

29# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 

30# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 

31# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 

32# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 

33# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 

34# 

35"""Refactored 'safe reference from dispatcher.py""" 

36 

37import operator 

38import sys 

39import traceback 

40import weakref 

41 

42 

43try: 

44 callable 

45except NameError: 

46 def callable(object): 

47 return hasattr(object, '__call__') 

48 

49 

50if sys.version_info < (3,): 

51 get_self = operator.attrgetter('im_self') 

52 get_func = operator.attrgetter('im_func') 

53else: 

54 get_self = operator.attrgetter('__self__') 

55 get_func = operator.attrgetter('__func__') 

56 

57 

58def safe_ref(target, on_delete=None): 

59 """Return a *safe* weak reference to a callable target. 

60 

61 - ``target``: The object to be weakly referenced, if it's a bound 

62 method reference, will create a BoundMethodWeakref, otherwise 

63 creates a simple weakref. 

64 

65 - ``on_delete``: If provided, will have a hard reference stored to 

66 the callable to be called after the safe reference goes out of 

67 scope with the reference object, (either a weakref or a 

68 BoundMethodWeakref) as argument. 

69 """ 

70 try: 

71 im_self = get_self(target) 

72 except AttributeError: 

73 if callable(on_delete): 

74 return weakref.ref(target, on_delete) 

75 else: 

76 return weakref.ref(target) 

77 else: 

78 if im_self is not None: 

79 # Turn a bound method into a BoundMethodWeakref instance. 

80 # Keep track of these instances for lookup by disconnect(). 

81 assert hasattr(target, 'im_func') or hasattr(target, '__func__'), ( 

82 "safe_ref target %r has im_self, but no im_func, " 

83 "don't know how to create reference" % target) 

84 reference = BoundMethodWeakref(target=target, on_delete=on_delete) 

85 return reference 

86 

87 

88class BoundMethodWeakref(object): 

89 """'Safe' and reusable weak references to instance methods. 

90 

91 BoundMethodWeakref objects provide a mechanism for referencing a 

92 bound method without requiring that the method object itself 

93 (which is normally a transient object) is kept alive. Instead, 

94 the BoundMethodWeakref object keeps weak references to both the 

95 object and the function which together define the instance method. 

96 

97 Attributes: 

98 

99 - ``key``: The identity key for the reference, calculated by the 

100 class's calculate_key method applied to the target instance method. 

101 

102 - ``deletion_methods``: Sequence of callable objects taking single 

103 argument, a reference to this object which will be called when 

104 *either* the target object or target function is garbage 

105 collected (i.e. when this object becomes invalid). These are 

106 specified as the on_delete parameters of safe_ref calls. 

107 

108 - ``weak_self``: Weak reference to the target object. 

109 

110 - ``weak_func``: Weak reference to the target function. 

111 

112 Class Attributes: 

113 

114 - ``_all_instances``: Class attribute pointing to all live 

115 BoundMethodWeakref objects indexed by the class's 

116 calculate_key(target) method applied to the target objects. 

117 This weak value dictionary is used to short-circuit creation so 

118 that multiple references to the same (object, function) pair 

119 produce the same BoundMethodWeakref instance. 

120 """ 

121 

122 _all_instances = weakref.WeakValueDictionary() 

123 

124 def __new__(cls, target, on_delete=None, *arguments, **named): 

125 """Create new instance or return current instance. 

126 

127 Basically this method of construction allows us to 

128 short-circuit creation of references to already- referenced 

129 instance methods. The key corresponding to the target is 

130 calculated, and if there is already an existing reference, 

131 that is returned, with its deletion_methods attribute updated. 

132 Otherwise the new instance is created and registered in the 

133 table of already-referenced methods. 

134 """ 

135 key = cls.calculate_key(target) 

136 current = cls._all_instances.get(key) 

137 if current is not None: 

138 current.deletion_methods.append(on_delete) 

139 return current 

140 else: 

141 base = super(BoundMethodWeakref, cls).__new__(cls) 

142 cls._all_instances[key] = base 

143 base.__init__(target, on_delete, *arguments, **named) 

144 return base 

145 

146 def __init__(self, target, on_delete=None): 

147 """Return a weak-reference-like instance for a bound method. 

148 

149 - ``target``: The instance-method target for the weak reference, 

150 must have im_self and im_func attributes and be 

151 reconstructable via the following, which is true of built-in 

152 instance methods:: 

153 

154 target.im_func.__get__( target.im_self ) 

155 

156 - ``on_delete``: Optional callback which will be called when 

157 this weak reference ceases to be valid (i.e. either the 

158 object or the function is garbage collected). Should take a 

159 single argument, which will be passed a pointer to this 

160 object. 

161 """ 

162 def remove(weak, self=self): 

163 """Set self.isDead to True when method or instance is destroyed.""" 

164 methods = self.deletion_methods[:] 

165 del self.deletion_methods[:] 

166 try: 

167 del self.__class__._all_instances[self.key] 

168 except KeyError: 

169 pass 

170 for function in methods: 

171 try: 

172 if callable(function): 

173 function(self) 

174 except Exception: 

175 try: 

176 traceback.print_exc() 

177 except AttributeError: 

178 e = sys.exc_info()[1] 

179 print ('Exception during saferef %s ' 

180 'cleanup function %s: %s' % (self, function, e)) 

181 self.deletion_methods = [on_delete] 

182 self.key = self.calculate_key(target) 

183 im_self = get_self(target) 

184 im_func = get_func(target) 

185 self.weak_self = weakref.ref(im_self, remove) 

186 self.weak_func = weakref.ref(im_func, remove) 

187 self.self_name = str(im_self) 

188 self.func_name = str(im_func.__name__) 

189 

190 def calculate_key(cls, target): 

191 """Calculate the reference key for this reference. 

192 

193 Currently this is a two-tuple of the id()'s of the target 

194 object and the target function respectively. 

195 """ 

196 return (id(get_self(target)), id(get_func(target))) 

197 calculate_key = classmethod(calculate_key) 

198 

199 def __str__(self): 

200 """Give a friendly representation of the object.""" 

201 return "{}({}.{})".format( 

202 self.__class__.__name__, 

203 self.self_name, 

204 self.func_name, 

205 ) 

206 

207 __repr__ = __str__ 

208 

209 def __nonzero__(self): 

210 """Whether we are still a valid reference.""" 

211 return self() is not None 

212 

213 def __cmp__(self, other): 

214 """Compare with another reference.""" 

215 if not isinstance(other, self.__class__): 

216 return cmp(self.__class__, type(other)) 

217 return cmp(self.key, other.key) 

218 

219 def __call__(self): 

220 """Return a strong reference to the bound method. 

221 

222 If the target cannot be retrieved, then will return None, 

223 otherwise returns a bound instance method for our object and 

224 function. 

225 

226 Note: You may call this method any number of times, as it does 

227 not invalidate the reference. 

228 """ 

229 target = self.weak_self() 

230 if target is not None: 

231 function = self.weak_func() 

232 if function is not None: 

233 return function.__get__(target) 

234 return None