ยปCore Development>Code coverage>Lib/weakref.py

Python code coverage for Lib/weakref.py

#countcontent
1n/a"""Weak reference support for Python.
2n/a
3n/aThis module is an implementation of PEP 205:
4n/a
5n/ahttp://www.python.org/dev/peps/pep-0205/
6n/a"""
7n/a
8n/a# Naming convention: Variables named "wr" are weak reference objects;
9n/a# they are called this instead of "ref" to avoid name collisions with
10n/a# the module-global ref() function imported from _weakref.
11n/a
12n/afrom _weakref import (
13n/a getweakrefcount,
14n/a getweakrefs,
15n/a ref,
16n/a proxy,
17n/a CallableProxyType,
18n/a ProxyType,
19n/a ReferenceType,
20n/a _remove_dead_weakref)
21n/a
22n/afrom _weakrefset import WeakSet, _IterationGuard
23n/a
24n/aimport collections # Import after _weakref to avoid circular import.
25n/aimport sys
26n/aimport itertools
27n/a
28n/aProxyTypes = (ProxyType, CallableProxyType)
29n/a
30n/a__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs",
31n/a "WeakKeyDictionary", "ReferenceType", "ProxyType",
32n/a "CallableProxyType", "ProxyTypes", "WeakValueDictionary",
33n/a "WeakSet", "WeakMethod", "finalize"]
34n/a
35n/a
36n/aclass WeakMethod(ref):
37n/a """
38n/a A custom `weakref.ref` subclass which simulates a weak reference to
39n/a a bound method, working around the lifetime problem of bound methods.
40n/a """
41n/a
42n/a __slots__ = "_func_ref", "_meth_type", "_alive", "__weakref__"
43n/a
44n/a def __new__(cls, meth, callback=None):
45n/a try:
46n/a obj = meth.__self__
47n/a func = meth.__func__
48n/a except AttributeError:
49n/a raise TypeError("argument should be a bound method, not {}"
50n/a .format(type(meth))) from None
51n/a def _cb(arg):
52n/a # The self-weakref trick is needed to avoid creating a reference
53n/a # cycle.
54n/a self = self_wr()
55n/a if self._alive:
56n/a self._alive = False
57n/a if callback is not None:
58n/a callback(self)
59n/a self = ref.__new__(cls, obj, _cb)
60n/a self._func_ref = ref(func, _cb)
61n/a self._meth_type = type(meth)
62n/a self._alive = True
63n/a self_wr = ref(self)
64n/a return self
65n/a
66n/a def __call__(self):
67n/a obj = super().__call__()
68n/a func = self._func_ref()
69n/a if obj is None or func is None:
70n/a return None
71n/a return self._meth_type(func, obj)
72n/a
73n/a def __eq__(self, other):
74n/a if isinstance(other, WeakMethod):
75n/a if not self._alive or not other._alive:
76n/a return self is other
77n/a return ref.__eq__(self, other) and self._func_ref == other._func_ref
78n/a return False
79n/a
80n/a def __ne__(self, other):
81n/a if isinstance(other, WeakMethod):
82n/a if not self._alive or not other._alive:
83n/a return self is not other
84n/a return ref.__ne__(self, other) or self._func_ref != other._func_ref
85n/a return True
86n/a
87n/a __hash__ = ref.__hash__
88n/a
89n/a
90n/aclass WeakValueDictionary(collections.MutableMapping):
91n/a """Mapping class that references values weakly.
92n/a
93n/a Entries in the dictionary will be discarded when no strong
94n/a reference to the value exists anymore
95n/a """
96n/a # We inherit the constructor without worrying about the input
97n/a # dictionary; since it uses our .update() method, we get the right
98n/a # checks (if the other dictionary is a WeakValueDictionary,
99n/a # objects are unwrapped on the way out, and we always wrap on the
100n/a # way in).
101n/a
102n/a def __init__(*args, **kw):
103n/a if not args:
104n/a raise TypeError("descriptor '__init__' of 'WeakValueDictionary' "
105n/a "object needs an argument")
106n/a self, *args = args
107n/a if len(args) > 1:
108n/a raise TypeError('expected at most 1 arguments, got %d' % len(args))
109n/a def remove(wr, selfref=ref(self), _atomic_removal=_remove_dead_weakref):
110n/a self = selfref()
111n/a if self is not None:
112n/a if self._iterating:
113n/a self._pending_removals.append(wr.key)
114n/a else:
115n/a # Atomic removal is necessary since this function
116n/a # can be called asynchronously by the GC
117n/a _atomic_removal(d, wr.key)
118n/a self._remove = remove
119n/a # A list of keys to be removed
120n/a self._pending_removals = []
121n/a self._iterating = set()
122n/a self.data = d = {}
123n/a self.update(*args, **kw)
124n/a
125n/a def _commit_removals(self):
126n/a l = self._pending_removals
127n/a d = self.data
128n/a # We shouldn't encounter any KeyError, because this method should
129n/a # always be called *before* mutating the dict.
130n/a while l:
131n/a key = l.pop()
132n/a _remove_dead_weakref(d, key)
133n/a
134n/a def __getitem__(self, key):
135n/a if self._pending_removals:
136n/a self._commit_removals()
137n/a o = self.data[key]()
138n/a if o is None:
139n/a raise KeyError(key)
140n/a else:
141n/a return o
142n/a
143n/a def __delitem__(self, key):
144n/a if self._pending_removals:
145n/a self._commit_removals()
146n/a del self.data[key]
147n/a
148n/a def __len__(self):
149n/a if self._pending_removals:
150n/a self._commit_removals()
151n/a return len(self.data)
152n/a
153n/a def __contains__(self, key):
154n/a if self._pending_removals:
155n/a self._commit_removals()
156n/a try:
157n/a o = self.data[key]()
158n/a except KeyError:
159n/a return False
160n/a return o is not None
161n/a
162n/a def __repr__(self):
163n/a return "<%s at %#x>" % (self.__class__.__name__, id(self))
164n/a
165n/a def __setitem__(self, key, value):
166n/a if self._pending_removals:
167n/a self._commit_removals()
168n/a self.data[key] = KeyedRef(value, self._remove, key)
169n/a
170n/a def copy(self):
171n/a if self._pending_removals:
172n/a self._commit_removals()
173n/a new = WeakValueDictionary()
174n/a for key, wr in self.data.items():
175n/a o = wr()
176n/a if o is not None:
177n/a new[key] = o
178n/a return new
179n/a
180n/a __copy__ = copy
181n/a
182n/a def __deepcopy__(self, memo):
183n/a from copy import deepcopy
184n/a if self._pending_removals:
185n/a self._commit_removals()
186n/a new = self.__class__()
187n/a for key, wr in self.data.items():
188n/a o = wr()
189n/a if o is not None:
190n/a new[deepcopy(key, memo)] = o
191n/a return new
192n/a
193n/a def get(self, key, default=None):
194n/a if self._pending_removals:
195n/a self._commit_removals()
196n/a try:
197n/a wr = self.data[key]
198n/a except KeyError:
199n/a return default
200n/a else:
201n/a o = wr()
202n/a if o is None:
203n/a # This should only happen
204n/a return default
205n/a else:
206n/a return o
207n/a
208n/a def items(self):
209n/a if self._pending_removals:
210n/a self._commit_removals()
211n/a with _IterationGuard(self):
212n/a for k, wr in self.data.items():
213n/a v = wr()
214n/a if v is not None:
215n/a yield k, v
216n/a
217n/a def keys(self):
218n/a if self._pending_removals:
219n/a self._commit_removals()
220n/a with _IterationGuard(self):
221n/a for k, wr in self.data.items():
222n/a if wr() is not None:
223n/a yield k
224n/a
225n/a __iter__ = keys
226n/a
227n/a def itervaluerefs(self):
228n/a """Return an iterator that yields the weak references to the values.
229n/a
230n/a The references are not guaranteed to be 'live' at the time
231n/a they are used, so the result of calling the references needs
232n/a to be checked before being used. This can be used to avoid
233n/a creating references that will cause the garbage collector to
234n/a keep the values around longer than needed.
235n/a
236n/a """
237n/a if self._pending_removals:
238n/a self._commit_removals()
239n/a with _IterationGuard(self):
240n/a yield from self.data.values()
241n/a
242n/a def values(self):
243n/a if self._pending_removals:
244n/a self._commit_removals()
245n/a with _IterationGuard(self):
246n/a for wr in self.data.values():
247n/a obj = wr()
248n/a if obj is not None:
249n/a yield obj
250n/a
251n/a def popitem(self):
252n/a if self._pending_removals:
253n/a self._commit_removals()
254n/a while True:
255n/a key, wr = self.data.popitem()
256n/a o = wr()
257n/a if o is not None:
258n/a return key, o
259n/a
260n/a def pop(self, key, *args):
261n/a if self._pending_removals:
262n/a self._commit_removals()
263n/a try:
264n/a o = self.data.pop(key)()
265n/a except KeyError:
266n/a o = None
267n/a if o is None:
268n/a if args:
269n/a return args[0]
270n/a else:
271n/a raise KeyError(key)
272n/a else:
273n/a return o
274n/a
275n/a def setdefault(self, key, default=None):
276n/a try:
277n/a o = self.data[key]()
278n/a except KeyError:
279n/a o = None
280n/a if o is None:
281n/a if self._pending_removals:
282n/a self._commit_removals()
283n/a self.data[key] = KeyedRef(default, self._remove, key)
284n/a return default
285n/a else:
286n/a return o
287n/a
288n/a def update(*args, **kwargs):
289n/a if not args:
290n/a raise TypeError("descriptor 'update' of 'WeakValueDictionary' "
291n/a "object needs an argument")
292n/a self, *args = args
293n/a if len(args) > 1:
294n/a raise TypeError('expected at most 1 arguments, got %d' % len(args))
295n/a dict = args[0] if args else None
296n/a if self._pending_removals:
297n/a self._commit_removals()
298n/a d = self.data
299n/a if dict is not None:
300n/a if not hasattr(dict, "items"):
301n/a dict = type({})(dict)
302n/a for key, o in dict.items():
303n/a d[key] = KeyedRef(o, self._remove, key)
304n/a if len(kwargs):
305n/a self.update(kwargs)
306n/a
307n/a def valuerefs(self):
308n/a """Return a list of weak references to the values.
309n/a
310n/a The references are not guaranteed to be 'live' at the time
311n/a they are used, so the result of calling the references needs
312n/a to be checked before being used. This can be used to avoid
313n/a creating references that will cause the garbage collector to
314n/a keep the values around longer than needed.
315n/a
316n/a """
317n/a if self._pending_removals:
318n/a self._commit_removals()
319n/a return list(self.data.values())
320n/a
321n/a
322n/aclass KeyedRef(ref):
323n/a """Specialized reference that includes a key corresponding to the value.
324n/a
325n/a This is used in the WeakValueDictionary to avoid having to create
326n/a a function object for each key stored in the mapping. A shared
327n/a callback object can use the 'key' attribute of a KeyedRef instead
328n/a of getting a reference to the key from an enclosing scope.
329n/a
330n/a """
331n/a
332n/a __slots__ = "key",
333n/a
334n/a def __new__(type, ob, callback, key):
335n/a self = ref.__new__(type, ob, callback)
336n/a self.key = key
337n/a return self
338n/a
339n/a def __init__(self, ob, callback, key):
340n/a super().__init__(ob, callback)
341n/a
342n/a
343n/aclass WeakKeyDictionary(collections.MutableMapping):
344n/a """ Mapping class that references keys weakly.
345n/a
346n/a Entries in the dictionary will be discarded when there is no
347n/a longer a strong reference to the key. This can be used to
348n/a associate additional data with an object owned by other parts of
349n/a an application without adding attributes to those objects. This
350n/a can be especially useful with objects that override attribute
351n/a accesses.
352n/a """
353n/a
354n/a def __init__(self, dict=None):
355n/a self.data = {}
356n/a def remove(k, selfref=ref(self)):
357n/a self = selfref()
358n/a if self is not None:
359n/a if self._iterating:
360n/a self._pending_removals.append(k)
361n/a else:
362n/a del self.data[k]
363n/a self._remove = remove
364n/a # A list of dead weakrefs (keys to be removed)
365n/a self._pending_removals = []
366n/a self._iterating = set()
367n/a self._dirty_len = False
368n/a if dict is not None:
369n/a self.update(dict)
370n/a
371n/a def _commit_removals(self):
372n/a # NOTE: We don't need to call this method before mutating the dict,
373n/a # because a dead weakref never compares equal to a live weakref,
374n/a # even if they happened to refer to equal objects.
375n/a # However, it means keys may already have been removed.
376n/a l = self._pending_removals
377n/a d = self.data
378n/a while l:
379n/a try:
380n/a del d[l.pop()]
381n/a except KeyError:
382n/a pass
383n/a
384n/a def _scrub_removals(self):
385n/a d = self.data
386n/a self._pending_removals = [k for k in self._pending_removals if k in d]
387n/a self._dirty_len = False
388n/a
389n/a def __delitem__(self, key):
390n/a self._dirty_len = True
391n/a del self.data[ref(key)]
392n/a
393n/a def __getitem__(self, key):
394n/a return self.data[ref(key)]
395n/a
396n/a def __len__(self):
397n/a if self._dirty_len and self._pending_removals:
398n/a # self._pending_removals may still contain keys which were
399n/a # explicitly removed, we have to scrub them (see issue #21173).
400n/a self._scrub_removals()
401n/a return len(self.data) - len(self._pending_removals)
402n/a
403n/a def __repr__(self):
404n/a return "<%s at %#x>" % (self.__class__.__name__, id(self))
405n/a
406n/a def __setitem__(self, key, value):
407n/a self.data[ref(key, self._remove)] = value
408n/a
409n/a def copy(self):
410n/a new = WeakKeyDictionary()
411n/a for key, value in self.data.items():
412n/a o = key()
413n/a if o is not None:
414n/a new[o] = value
415n/a return new
416n/a
417n/a __copy__ = copy
418n/a
419n/a def __deepcopy__(self, memo):
420n/a from copy import deepcopy
421n/a new = self.__class__()
422n/a for key, value in self.data.items():
423n/a o = key()
424n/a if o is not None:
425n/a new[o] = deepcopy(value, memo)
426n/a return new
427n/a
428n/a def get(self, key, default=None):
429n/a return self.data.get(ref(key),default)
430n/a
431n/a def __contains__(self, key):
432n/a try:
433n/a wr = ref(key)
434n/a except TypeError:
435n/a return False
436n/a return wr in self.data
437n/a
438n/a def items(self):
439n/a with _IterationGuard(self):
440n/a for wr, value in self.data.items():
441n/a key = wr()
442n/a if key is not None:
443n/a yield key, value
444n/a
445n/a def keys(self):
446n/a with _IterationGuard(self):
447n/a for wr in self.data:
448n/a obj = wr()
449n/a if obj is not None:
450n/a yield obj
451n/a
452n/a __iter__ = keys
453n/a
454n/a def values(self):
455n/a with _IterationGuard(self):
456n/a for wr, value in self.data.items():
457n/a if wr() is not None:
458n/a yield value
459n/a
460n/a def keyrefs(self):
461n/a """Return a list of weak references to the keys.
462n/a
463n/a The references are not guaranteed to be 'live' at the time
464n/a they are used, so the result of calling the references needs
465n/a to be checked before being used. This can be used to avoid
466n/a creating references that will cause the garbage collector to
467n/a keep the keys around longer than needed.
468n/a
469n/a """
470n/a return list(self.data)
471n/a
472n/a def popitem(self):
473n/a self._dirty_len = True
474n/a while True:
475n/a key, value = self.data.popitem()
476n/a o = key()
477n/a if o is not None:
478n/a return o, value
479n/a
480n/a def pop(self, key, *args):
481n/a self._dirty_len = True
482n/a return self.data.pop(ref(key), *args)
483n/a
484n/a def setdefault(self, key, default=None):
485n/a return self.data.setdefault(ref(key, self._remove),default)
486n/a
487n/a def update(self, dict=None, **kwargs):
488n/a d = self.data
489n/a if dict is not None:
490n/a if not hasattr(dict, "items"):
491n/a dict = type({})(dict)
492n/a for key, value in dict.items():
493n/a d[ref(key, self._remove)] = value
494n/a if len(kwargs):
495n/a self.update(kwargs)
496n/a
497n/a
498n/aclass finalize:
499n/a """Class for finalization of weakrefable objects
500n/a
501n/a finalize(obj, func, *args, **kwargs) returns a callable finalizer
502n/a object which will be called when obj is garbage collected. The
503n/a first time the finalizer is called it evaluates func(*arg, **kwargs)
504n/a and returns the result. After this the finalizer is dead, and
505n/a calling it just returns None.
506n/a
507n/a When the program exits any remaining finalizers for which the
508n/a atexit attribute is true will be run in reverse order of creation.
509n/a By default atexit is true.
510n/a """
511n/a
512n/a # Finalizer objects don't have any state of their own. They are
513n/a # just used as keys to lookup _Info objects in the registry. This
514n/a # ensures that they cannot be part of a ref-cycle.
515n/a
516n/a __slots__ = ()
517n/a _registry = {}
518n/a _shutdown = False
519n/a _index_iter = itertools.count()
520n/a _dirty = False
521n/a _registered_with_atexit = False
522n/a
523n/a class _Info:
524n/a __slots__ = ("weakref", "func", "args", "kwargs", "atexit", "index")
525n/a
526n/a def __init__(self, obj, func, *args, **kwargs):
527n/a if not self._registered_with_atexit:
528n/a # We may register the exit function more than once because
529n/a # of a thread race, but that is harmless
530n/a import atexit
531n/a atexit.register(self._exitfunc)
532n/a finalize._registered_with_atexit = True
533n/a info = self._Info()
534n/a info.weakref = ref(obj, self)
535n/a info.func = func
536n/a info.args = args
537n/a info.kwargs = kwargs or None
538n/a info.atexit = True
539n/a info.index = next(self._index_iter)
540n/a self._registry[self] = info
541n/a finalize._dirty = True
542n/a
543n/a def __call__(self, _=None):
544n/a """If alive then mark as dead and return func(*args, **kwargs);
545n/a otherwise return None"""
546n/a info = self._registry.pop(self, None)
547n/a if info and not self._shutdown:
548n/a return info.func(*info.args, **(info.kwargs or {}))
549n/a
550n/a def detach(self):
551n/a """If alive then mark as dead and return (obj, func, args, kwargs);
552n/a otherwise return None"""
553n/a info = self._registry.get(self)
554n/a obj = info and info.weakref()
555n/a if obj is not None and self._registry.pop(self, None):
556n/a return (obj, info.func, info.args, info.kwargs or {})
557n/a
558n/a def peek(self):
559n/a """If alive then return (obj, func, args, kwargs);
560n/a otherwise return None"""
561n/a info = self._registry.get(self)
562n/a obj = info and info.weakref()
563n/a if obj is not None:
564n/a return (obj, info.func, info.args, info.kwargs or {})
565n/a
566n/a @property
567n/a def alive(self):
568n/a """Whether finalizer is alive"""
569n/a return self in self._registry
570n/a
571n/a @property
572n/a def atexit(self):
573n/a """Whether finalizer should be called at exit"""
574n/a info = self._registry.get(self)
575n/a return bool(info) and info.atexit
576n/a
577n/a @atexit.setter
578n/a def atexit(self, value):
579n/a info = self._registry.get(self)
580n/a if info:
581n/a info.atexit = bool(value)
582n/a
583n/a def __repr__(self):
584n/a info = self._registry.get(self)
585n/a obj = info and info.weakref()
586n/a if obj is None:
587n/a return '<%s object at %#x; dead>' % (type(self).__name__, id(self))
588n/a else:
589n/a return '<%s object at %#x; for %r at %#x>' % \
590n/a (type(self).__name__, id(self), type(obj).__name__, id(obj))
591n/a
592n/a @classmethod
593n/a def _select_for_exit(cls):
594n/a # Return live finalizers marked for exit, oldest first
595n/a L = [(f,i) for (f,i) in cls._registry.items() if i.atexit]
596n/a L.sort(key=lambda item:item[1].index)
597n/a return [f for (f,i) in L]
598n/a
599n/a @classmethod
600n/a def _exitfunc(cls):
601n/a # At shutdown invoke finalizers for which atexit is true.
602n/a # This is called once all other non-daemonic threads have been
603n/a # joined.
604n/a reenable_gc = False
605n/a try:
606n/a if cls._registry:
607n/a import gc
608n/a if gc.isenabled():
609n/a reenable_gc = True
610n/a gc.disable()
611n/a pending = None
612n/a while True:
613n/a if pending is None or finalize._dirty:
614n/a pending = cls._select_for_exit()
615n/a finalize._dirty = False
616n/a if not pending:
617n/a break
618n/a f = pending.pop()
619n/a try:
620n/a # gc is disabled, so (assuming no daemonic
621n/a # threads) the following is the only line in
622n/a # this function which might trigger creation
623n/a # of a new finalizer
624n/a f()
625n/a except Exception:
626n/a sys.excepthook(*sys.exc_info())
627n/a assert f not in cls._registry
628n/a finally:
629n/a # prevent any more finalizers from executing during shutdown
630n/a finalize._shutdown = True
631n/a if reenable_gc:
632n/a gc.enable()