diff --git a/devlib/utils/misc.py b/devlib/utils/misc.py index 54ba2b1..4d488b6 100644 --- a/devlib/utils/misc.py +++ b/devlib/utils/misc.py @@ -19,11 +19,13 @@ Miscellaneous functions that don't fit anywhere else. """ from __future__ import division +from contextlib import contextmanager from functools import partial, reduce from itertools import groupby from operator import itemgetter import ctypes +import functools import logging import os import pkgutil @@ -38,6 +40,11 @@ import wrapt import warnings +try: + from contextlib import ExitStack +except AttributeError: + from contextlib2 import ExitStack + from past.builtins import basestring # pylint: disable=redefined-builtin @@ -695,3 +702,19 @@ def memoized(wrapped, instance, args, kwargs): # pylint: disable=unused-argumen return __memo_cache[id_string] return memoize_wrapper(*args, **kwargs) + +@contextmanager +def batch_contextmanager(f, kwargs_list): + """ + Return a context manager that will call the ``f`` callable with the keyword + arguments dict in the given list, in one go. + + :param f: Callable expected to return a context manager. + + :param kwargs_list: list of kwargs dictionaries to be used to call ``f``. + :type kwargs_list: list(dict) + """ + with ExitStack() as stack: + for kwargs in kwargs_list: + stack.enter_context(f(**kwargs)) + yield diff --git a/setup.py b/setup.py index 2c30895..df3377d 100644 --- a/setup.py +++ b/setup.py @@ -85,6 +85,7 @@ params = dict( 'wrapt', # Basic for construction of decorator functions 'future', # Python 2-3 compatibility 'enum34;python_version<"3.4"', # Enums for Python < 3.4 + 'contextlib2;python_version<"3.0"', # Python 3 contextlib backport for Python 2 'numpy<=1.16.4; python_version<"3"', 'numpy; python_version>="3"', 'pandas<=0.24.2; python_version<"3"',