Mercurial > repos > shellac > sam_consensus_v3
diff env/lib/python3.9/site-packages/boltons/gcutils.py @ 0:4f3585e2f14b draft default tip
"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author | shellac |
---|---|
date | Mon, 22 Mar 2021 18:12:50 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/env/lib/python3.9/site-packages/boltons/gcutils.py Mon Mar 22 18:12:50 2021 +0000 @@ -0,0 +1,136 @@ +# -*- coding: utf-8 -*- +"""The Python Garbage Collector (`GC`_) doesn't usually get too much +attention, probably because: + + - Python's `reference counting`_ effectively handles the vast majority of + unused objects + - People are slowly learning to avoid implementing `object.__del__()`_ + - The collection itself strikes a good balance between simplicity and + power (`tunable generation sizes`_) + - The collector itself is fast and rarely the cause of long pauses + associated with GC in other runtimes + +Even so, for many applications, the time will come when the developer +will need to track down: + + - Circular references + - Misbehaving objects (locks, ``__del__()``) + - Memory leaks + - Or just ways to shave off a couple percent of execution time + +Thanks to the :mod:`gc` module, the GC is a well-instrumented entry +point for exactly these tasks, and ``gcutils`` aims to facilitate it +further. + +.. _GC: https://docs.python.org/2/glossary.html#term-garbage-collection +.. _reference counting: https://docs.python.org/2/glossary.html#term-reference-count +.. _object.__del__(): https://docs.python.org/2/glossary.html#term-reference-count +.. _tunable generation sizes: https://docs.python.org/2/library/gc.html#gc.set_threshold +""" +# TODO: type survey + +from __future__ import print_function + +import gc +import sys + +__all__ = ['get_all', 'GCToggler', 'toggle_gc', 'toggle_gc_postcollect'] + + +def get_all(type_obj, include_subtypes=True): + """Get a list containing all instances of a given type. This will + work for the vast majority of types out there. + + >>> class Ratking(object): pass + >>> wiki, hak, sport = Ratking(), Ratking(), Ratking() + >>> len(get_all(Ratking)) + 3 + + However, there are some exceptions. For example, ``get_all(bool)`` + returns an empty list because ``True`` and ``False`` are + themselves built-in and not tracked. + + >>> get_all(bool) + [] + + Still, it's not hard to see how this functionality can be used to + find all instances of a leaking type and track them down further + using :func:`gc.get_referrers` and :func:`gc.get_referents`. + + ``get_all()`` is optimized such that getting instances of + user-created types is quite fast. Setting *include_subtypes* to + ``False`` will further increase performance in cases where + instances of subtypes aren't required. + + .. note:: + + There are no guarantees about the state of objects returned by + ``get_all()``, especially in concurrent environments. For + instance, it is possible for an object to be in the middle of + executing its ``__init__()`` and be only partially constructed. + """ + # TODO: old-style classes + if not isinstance(type_obj, type): + raise TypeError('expected a type, not %r' % type_obj) + try: + type_is_tracked = gc.is_tracked(type_obj) + except AttributeError: + type_is_tracked = False # Python 2.6 and below don't get the speedup + if type_is_tracked: + to_check = gc.get_referrers(type_obj) + else: + to_check = gc.get_objects() + + if include_subtypes: + ret = [x for x in to_check if isinstance(x, type_obj)] + else: + ret = [x for x in to_check if type(x) is type_obj] + return ret + + +_IS_PYPY = '__pypy__' in sys.builtin_module_names +if _IS_PYPY: + # pypy's gc is just different, y'all + del get_all + + +class GCToggler(object): + """The ``GCToggler`` is a context-manager that allows one to safely + take more control of your garbage collection schedule. Anecdotal + experience says certain object-creation-heavy tasks see speedups + of around 10% by simply doing one explicit collection at the very + end, especially if most of the objects will stay resident. + + Two GCTogglers are already present in the ``gcutils`` module: + + - :data:`toggle_gc` simply turns off GC at context entrance, and + re-enables at exit + - :data:`toggle_gc_postcollect` does the same, but triggers an + explicit collection after re-enabling. + + >>> with toggle_gc: + ... x = [object() for i in range(1000)] + + Between those two instances, the ``GCToggler`` type probably won't + be used much directly, but is documented for inheritance purposes. + """ + def __init__(self, postcollect=False): + self.postcollect = postcollect + + def __enter__(self): + gc.disable() + + def __exit__(self, exc_type, exc_val, exc_tb): + gc.enable() + if self.postcollect: + gc.collect() + + +toggle_gc = GCToggler() +"""A context manager for disabling GC for a code block. See +:class:`GCToggler` for more details.""" + + +toggle_gc_postcollect = GCToggler(postcollect=True) +"""A context manager for disabling GC for a code block, and collecting +before re-enabling. See :class:`GCToggler` for more details."""