123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- """
- Module for testing automatic garbage collection of objects
- .. autosummary::
- :toctree: generated/
- set_gc_state - enable or disable garbage collection
- gc_state - context manager for given state of garbage collector
- assert_deallocated - context manager to check for circular references on object
- """
- import weakref
- import gc
- from contextlib import contextmanager
- from platform import python_implementation
- __all__ = ['set_gc_state', 'gc_state', 'assert_deallocated']
- IS_PYPY = python_implementation() == 'PyPy'
- class ReferenceError(AssertionError):
- pass
- def set_gc_state(state):
- """ Set status of garbage collector """
- if gc.isenabled() == state:
- return
- if state:
- gc.enable()
- else:
- gc.disable()
- @contextmanager
- def gc_state(state):
- """ Context manager to set state of garbage collector to `state`
- Parameters
- ----------
- state : bool
- True for gc enabled, False for disabled
- Examples
- --------
- >>> with gc_state(False):
- ... assert not gc.isenabled()
- >>> with gc_state(True):
- ... assert gc.isenabled()
- """
- orig_state = gc.isenabled()
- set_gc_state(state)
- yield
- set_gc_state(orig_state)
- @contextmanager
- def assert_deallocated(func, *args, **kwargs):
- """Context manager to check that object is deallocated
- This is useful for checking that an object can be freed directly by
- reference counting, without requiring gc to break reference cycles.
- GC is disabled inside the context manager.
- This check is not available on PyPy.
- Parameters
- ----------
- func : callable
- Callable to create object to check
- \\*args : sequence
- positional arguments to `func` in order to create object to check
- \\*\\*kwargs : dict
- keyword arguments to `func` in order to create object to check
- Examples
- --------
- >>> class C: pass
- >>> with assert_deallocated(C) as c:
- ... # do something
- ... del c
- >>> class C:
- ... def __init__(self):
- ... self._circular = self # Make circular reference
- >>> with assert_deallocated(C) as c: #doctest: +IGNORE_EXCEPTION_DETAIL
- ... # do something
- ... del c
- Traceback (most recent call last):
- ...
- ReferenceError: Remaining reference(s) to object
- """
- if IS_PYPY:
- raise RuntimeError("assert_deallocated is unavailable on PyPy")
- with gc_state(False):
- obj = func(*args, **kwargs)
- ref = weakref.ref(obj)
- yield obj
- del obj
- if ref() is not None:
- raise ReferenceError("Remaining reference(s) to object")
|