github.com/grumpyhome/grumpy@v0.3.1-0.20201208125205-7b775405bdf1/grumpy-runtime-src/third_party/stdlib/weakref.py (about) 1 """Weak reference support for Python. 2 3 This module is an implementation of PEP 205: 4 5 http://www.python.org/dev/peps/pep-0205/ 6 """ 7 8 # Naming convention: Variables named "wr" are weak reference objects; 9 # they are called this instead of "ref" to avoid name collisions with 10 # the module-global ref() function imported from _weakref. 11 12 import UserDict 13 14 #from _weakref import ( 15 # getweakrefcount, 16 # getweakrefs, 17 # ref, 18 # proxy, 19 # CallableProxyType, 20 # ProxyType, 21 # ReferenceType) 22 23 from '__go__/grumpy' import WeakRefType as ReferenceType 24 ref = ReferenceType 25 26 import _weakrefset 27 WeakSet = _weakrefset.WeakSet 28 _IterationGuard = _weakrefset._IterationGuard 29 30 import exceptions 31 ReferenceError = exceptions.ReferenceError 32 33 34 #ProxyTypes = (ProxyType, CallableProxyType) 35 36 #__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs", 37 # "WeakKeyDictionary", "ReferenceError", "ReferenceType", "ProxyType", 38 # "CallableProxyType", "ProxyTypes", "WeakValueDictionary", 'WeakSet'] 39 40 41 class WeakValueDictionary(UserDict.UserDict): 42 """Mapping class that references values weakly. 43 44 Entries in the dictionary will be discarded when no strong 45 reference to the value exists anymore 46 """ 47 # We inherit the constructor without worrying about the input 48 # dictionary; since it uses our .update() method, we get the right 49 # checks (if the other dictionary is a WeakValueDictionary, 50 # objects are unwrapped on the way out, and we always wrap on the 51 # way in). 52 53 def __init__(*args, **kw): 54 if not args: 55 raise TypeError("descriptor '__init__' of 'WeakValueDictionary' " 56 "object needs an argument") 57 self = args[0] 58 args = args[1:] 59 if len(args) > 1: 60 raise TypeError('expected at most 1 arguments, got %d' % len(args)) 61 def remove(wr, selfref=ref(self)): 62 self = selfref() 63 if self is not None: 64 if self._iterating: 65 self._pending_removals.append(wr.key) 66 else: 67 del self.data[wr.key] 68 self._remove = remove 69 # A list of keys to be removed 70 self._pending_removals = [] 71 self._iterating = set() 72 UserDict.UserDict.__init__(self, *args, **kw) 73 74 def _commit_removals(self): 75 l = self._pending_removals 76 d = self.data 77 # We shouldn't encounter any KeyError, because this method should 78 # always be called *before* mutating the dict. 79 while l: 80 del d[l.pop()] 81 82 def __getitem__(self, key): 83 o = self.data[key]() 84 if o is None: 85 raise KeyError, key 86 else: 87 return o 88 89 def __delitem__(self, key): 90 if self._pending_removals: 91 self._commit_removals() 92 del self.data[key] 93 94 def __contains__(self, key): 95 try: 96 o = self.data[key]() 97 except KeyError: 98 return False 99 return o is not None 100 101 def has_key(self, key): 102 try: 103 o = self.data[key]() 104 except KeyError: 105 return False 106 return o is not None 107 108 def __repr__(self): 109 return "<WeakValueDictionary at %s>" % id(self) 110 111 def __setitem__(self, key, value): 112 if self._pending_removals: 113 self._commit_removals() 114 self.data[key] = KeyedRef(value, self._remove, key) 115 116 def clear(self): 117 if self._pending_removals: 118 self._commit_removals() 119 self.data.clear() 120 121 def copy(self): 122 new = WeakValueDictionary() 123 for key, wr in self.data.items(): 124 o = wr() 125 if o is not None: 126 new[key] = o 127 return new 128 129 __copy__ = copy 130 131 def __deepcopy__(self, memo): 132 import copy 133 new = self.__class__() 134 for key, wr in self.data.items(): 135 o = wr() 136 if o is not None: 137 new[copy.deepcopy(key, memo)] = o 138 return new 139 140 def get(self, key, default=None): 141 try: 142 wr = self.data[key] 143 except KeyError: 144 return default 145 else: 146 o = wr() 147 if o is None: 148 # This should only happen 149 return default 150 else: 151 return o 152 153 def items(self): 154 L = [] 155 for key, wr in self.data.items(): 156 o = wr() 157 if o is not None: 158 L.append((key, o)) 159 return L 160 161 def iteritems(self): 162 with _IterationGuard(self): 163 for wr in self.data.itervalues(): 164 value = wr() 165 if value is not None: 166 yield wr.key, value 167 168 def iterkeys(self): 169 with _IterationGuard(self): 170 for k in self.data.iterkeys(): 171 yield k 172 173 __iter__ = iterkeys 174 175 def itervaluerefs(self): 176 """Return an iterator that yields the weak references to the values. 177 178 The references are not guaranteed to be 'live' at the time 179 they are used, so the result of calling the references needs 180 to be checked before being used. This can be used to avoid 181 creating references that will cause the garbage collector to 182 keep the values around longer than needed. 183 184 """ 185 with _IterationGuard(self): 186 for wr in self.data.itervalues(): 187 yield wr 188 189 def itervalues(self): 190 with _IterationGuard(self): 191 for wr in self.data.itervalues(): 192 obj = wr() 193 if obj is not None: 194 yield obj 195 196 def popitem(self): 197 if self._pending_removals: 198 self._commit_removals() 199 while 1: 200 key, wr = self.data.popitem() 201 o = wr() 202 if o is not None: 203 return key, o 204 205 def pop(self, key, *args): 206 if self._pending_removals: 207 self._commit_removals() 208 try: 209 o = self.data.pop(key)() 210 except KeyError: 211 if args: 212 return args[0] 213 raise 214 if o is None: 215 raise KeyError, key 216 else: 217 return o 218 219 def setdefault(self, key, default=None): 220 try: 221 wr = self.data[key] 222 except KeyError: 223 if self._pending_removals: 224 self._commit_removals() 225 self.data[key] = KeyedRef(default, self._remove, key) 226 return default 227 else: 228 return wr() 229 230 def update(*args, **kwargs): 231 if not args: 232 raise TypeError("descriptor 'update' of 'WeakValueDictionary' " 233 "object needs an argument") 234 self = args[0] 235 args = args[1:] 236 if len(args) > 1: 237 raise TypeError('expected at most 1 arguments, got %d' % len(args)) 238 dict = args[0] if args else None 239 if self._pending_removals: 240 self._commit_removals() 241 d = self.data 242 if dict is not None: 243 if not hasattr(dict, "items"): 244 dict = type({})(dict) 245 for key, o in dict.items(): 246 d[key] = KeyedRef(o, self._remove, key) 247 if len(kwargs): 248 self.update(kwargs) 249 250 def valuerefs(self): 251 """Return a list of weak references to the values. 252 253 The references are not guaranteed to be 'live' at the time 254 they are used, so the result of calling the references needs 255 to be checked before being used. This can be used to avoid 256 creating references that will cause the garbage collector to 257 keep the values around longer than needed. 258 259 """ 260 return self.data.values() 261 262 def values(self): 263 L = [] 264 for wr in self.data.values(): 265 o = wr() 266 if o is not None: 267 L.append(o) 268 return L 269 270 271 class KeyedRef(ref): 272 """Specialized reference that includes a key corresponding to the value. 273 274 This is used in the WeakValueDictionary to avoid having to create 275 a function object for each key stored in the mapping. A shared 276 callback object can use the 'key' attribute of a KeyedRef instead 277 of getting a reference to the key from an enclosing scope. 278 279 """ 280 281 __slots__ = "key", 282 283 def __new__(type, ob, callback, key): 284 self = ref.__new__(type, ob, callback) 285 self.key = key 286 return self 287 288 def __init__(self, ob, callback, key): 289 super(KeyedRef, self).__init__(ob, callback) 290 291 292 class WeakKeyDictionary(UserDict.UserDict): 293 """ Mapping class that references keys weakly. 294 295 Entries in the dictionary will be discarded when there is no 296 longer a strong reference to the key. This can be used to 297 associate additional data with an object owned by other parts of 298 an application without adding attributes to those objects. This 299 can be especially useful with objects that override attribute 300 accesses. 301 """ 302 303 def __init__(self, dict=None): 304 self.data = {} 305 def remove(k, selfref=ref(self)): 306 self = selfref() 307 if self is not None: 308 if self._iterating: 309 self._pending_removals.append(k) 310 else: 311 del self.data[k] 312 self._remove = remove 313 # A list of dead weakrefs (keys to be removed) 314 self._pending_removals = [] 315 self._iterating = set() 316 if dict is not None: 317 self.update(dict) 318 319 def _commit_removals(self): 320 # NOTE: We don't need to call this method before mutating the dict, 321 # because a dead weakref never compares equal to a live weakref, 322 # even if they happened to refer to equal objects. 323 # However, it means keys may already have been removed. 324 l = self._pending_removals 325 d = self.data 326 while l: 327 try: 328 del d[l.pop()] 329 except KeyError: 330 pass 331 332 def __delitem__(self, key): 333 del self.data[ref(key)] 334 335 def __getitem__(self, key): 336 return self.data[ref(key)] 337 338 def __repr__(self): 339 return "<WeakKeyDictionary at %s>" % id(self) 340 341 def __setitem__(self, key, value): 342 self.data[ref(key, self._remove)] = value 343 344 def copy(self): 345 new = WeakKeyDictionary() 346 for key, value in self.data.items(): 347 o = key() 348 if o is not None: 349 new[o] = value 350 return new 351 352 __copy__ = copy 353 354 def __deepcopy__(self, memo): 355 import copy 356 new = self.__class__() 357 for key, value in self.data.items(): 358 o = key() 359 if o is not None: 360 new[o] = copy.deepcopy(value, memo) 361 return new 362 363 def get(self, key, default=None): 364 return self.data.get(ref(key),default) 365 366 def has_key(self, key): 367 try: 368 wr = ref(key) 369 except TypeError: 370 return 0 371 return wr in self.data 372 373 def __contains__(self, key): 374 try: 375 wr = ref(key) 376 except TypeError: 377 return 0 378 return wr in self.data 379 380 def items(self): 381 L = [] 382 for key, value in self.data.items(): 383 o = key() 384 if o is not None: 385 L.append((o, value)) 386 return L 387 388 def iteritems(self): 389 with _IterationGuard(self): 390 for wr, value in self.data.iteritems(): 391 key = wr() 392 if key is not None: 393 yield key, value 394 395 def iterkeyrefs(self): 396 """Return an iterator that yields the weak references to the keys. 397 398 The references are not guaranteed to be 'live' at the time 399 they are used, so the result of calling the references needs 400 to be checked before being used. This can be used to avoid 401 creating references that will cause the garbage collector to 402 keep the keys around longer than needed. 403 404 """ 405 with _IterationGuard(self): 406 for wr in self.data.iterkeys(): 407 yield wr 408 409 def iterkeys(self): 410 with _IterationGuard(self): 411 for wr in self.data.iterkeys(): 412 obj = wr() 413 if obj is not None: 414 yield obj 415 416 __iter__ = iterkeys 417 418 def itervalues(self): 419 with _IterationGuard(self): 420 for value in self.data.itervalues(): 421 yield value 422 423 def keyrefs(self): 424 """Return a list of weak references to the keys. 425 426 The references are not guaranteed to be 'live' at the time 427 they are used, so the result of calling the references needs 428 to be checked before being used. This can be used to avoid 429 creating references that will cause the garbage collector to 430 keep the keys around longer than needed. 431 432 """ 433 return self.data.keys() 434 435 def keys(self): 436 L = [] 437 for wr in self.data.keys(): 438 o = wr() 439 if o is not None: 440 L.append(o) 441 return L 442 443 def popitem(self): 444 while 1: 445 key, value = self.data.popitem() 446 o = key() 447 if o is not None: 448 return o, value 449 450 def pop(self, key, *args): 451 return self.data.pop(ref(key), *args) 452 453 def setdefault(self, key, default=None): 454 return self.data.setdefault(ref(key, self._remove),default) 455 456 def update(self, dict=None, **kwargs): 457 d = self.data 458 if dict is not None: 459 if not hasattr(dict, "items"): 460 dict = type({})(dict) 461 for key, value in dict.items(): 462 d[ref(key, self._remove)] = value 463 if len(kwargs): 464 self.update(kwargs)