wmaee.core.utils
1import os 2import uuid 3import shutil 4import contextlib 5import collections.abc 6from typing import Dict, Type, Any, Optional 7 8 9# this beautiful solution was taken from: 10# https://stackoverflow.com/questions/2059482/temporarily-modify-the-current-processs-environment 11@contextlib.contextmanager 12def override_environ(*remove: str, **update): 13 """ 14 Temporarily updates the ``os.environ`` dictionary in-place. 15 16 The ``os.environ`` dictionary is updated in-place so that the modification 17 is sure to work in all situations. 18 19 :param remove: Environment variables to remove. 20 :type remove: str 21 :param update: Dictionary of environment variables and values to add/update. 22 """ 23 env = os.environ 24 update = update or {} 25 remove = remove or [] 26 27 # List of environment variables being updated or removed. 28 stomped = (set(update.keys()) | set(remove)) & set(env.keys()) 29 # Environment variables and values to restore on exit. 30 update_after = {k: env[k] for k in stomped} 31 # Environment variables and values to remove on exit. 32 remove_after = frozenset(k for k in update if k not in env) 33 34 try: 35 env.update(update) 36 [env.pop(k, None) for k in remove] 37 yield 38 finally: 39 env.update(update_after) 40 [env.pop(k) for k in remove_after] 41 42 43# class working_directory(object): 44# """ 45# A convenience class which syntactic sugar, allowing the user to change the directories. 46# Can also be nested. 47# """ 48 49# def __init__(self, name: Optional[str] = None, prefix: Optional[str] = None, delete: bool =False): 50# """ 51# Constructs a working_directory object 52# :param name: name of the directory if None is given `os.getcwd()` will be used (default is `None`) 53# :type name: Optional[str] 54# :param prefix: a prefix where to locate the directory (default is `None`) 55# :type prefix: Optional[str] 56# :param delete: whether to delete the directory after a with clause (default is `False`) 57# :type delete: bool 58# """ 59# self._name = str(uuid.uuid4()) if not name else name 60# self._delete = delete 61# self._curr_dir = os.getcwd() 62# self._active = False 63# if prefix is not None: 64# self._name = os.path.join(prefix, self._name) 65 66# def __enter__(self): 67# if not os.path.exists(self._name): 68# os.mkdir(self._name) 69# os.chdir(self._name) 70# self._active = True 71# return self 72 73# def __exit__(self, exc_type, exc_val, exc_tb): 74# os.chdir(self._curr_dir) 75# if self._delete: 76# shutil.rmtree(self._name) 77# self._active = False 78 79# @property 80# def name(self): 81# return self._name 82 83# @property 84# def active(self): 85# return self._active 86 87 88def merge(*dicts: Dict[Any, Any], factory: Type = dict, **kwargs) -> Dict[Any, Any]: 89 """ 90 Merge all specified dictionaries in {dicts} into a single one. Moreover, {kwargs} will be included. In case 91 duplicate keys exist, the order of passing the dictionaries will determine which values will sustain for the keys. 92 The last updated is carried out using {kwargs} 93 94 :param dicts: the dictionaries to merge 95 :type dicts: Dict[Any, Any] 96 :param factory: the constructor of the mapping type to create (default is `dict`) 97 :type factory: Type 98 :return: a merged dictionary of type {factory} 99 :rtype: Dict[Any, Any] 100 """ 101 102 merged = factory() 103 for dictionary in dicts: 104 merged.update(dictionary) 105 merged.update(kwargs) 106 return merged 107 108 109def _wrap_in_iterable(o, factory=tuple): 110 return factory((o,)) 111 112 113def ensure_iterable(o, exclude=(str, bytes), factory=tuple): 114 """ 115 wraps an object {o} into an iterable it is not and iterable. the type of the iterable is specified by {factory} 116 :param o: the object to wrap 117 :param exclude: type list of iterable objects which need wrapping (default is (str, bytes)) 118 :type exclude: Iterable[type] 119 :param factory: the Iterable type in which {o} should be wrapped 120 :type factory: type 121 :rtype: Iterable 122 """ 123 if isinstance(o, collections.abc.Iterable): 124 return o if not isinstance(o, exclude) else _wrap_in_iterable(o, factory=factory) 125 else: 126 return _wrap_in_iterable(o, factory=factory)
@contextlib.contextmanager
def
override_environ(*remove: str, **update):
13@contextlib.contextmanager 14def override_environ(*remove: str, **update): 15 """ 16 Temporarily updates the ``os.environ`` dictionary in-place. 17 18 The ``os.environ`` dictionary is updated in-place so that the modification 19 is sure to work in all situations. 20 21 :param remove: Environment variables to remove. 22 :type remove: str 23 :param update: Dictionary of environment variables and values to add/update. 24 """ 25 env = os.environ 26 update = update or {} 27 remove = remove or [] 28 29 # List of environment variables being updated or removed. 30 stomped = (set(update.keys()) | set(remove)) & set(env.keys()) 31 # Environment variables and values to restore on exit. 32 update_after = {k: env[k] for k in stomped} 33 # Environment variables and values to remove on exit. 34 remove_after = frozenset(k for k in update if k not in env) 35 36 try: 37 env.update(update) 38 [env.pop(k, None) for k in remove] 39 yield 40 finally: 41 env.update(update_after) 42 [env.pop(k) for k in remove_after]
Temporarily updates the os.environ dictionary in-place.
The os.environ dictionary is updated in-place so that the modification
is sure to work in all situations.
Parameters
- remove: Environment variables to remove.
- update: Dictionary of environment variables and values to add/update.
def
merge( *dicts: Dict[Any, Any], factory: Type = <class 'dict'>, **kwargs) -> Dict[Any, Any]:
90def merge(*dicts: Dict[Any, Any], factory: Type = dict, **kwargs) -> Dict[Any, Any]: 91 """ 92 Merge all specified dictionaries in {dicts} into a single one. Moreover, {kwargs} will be included. In case 93 duplicate keys exist, the order of passing the dictionaries will determine which values will sustain for the keys. 94 The last updated is carried out using {kwargs} 95 96 :param dicts: the dictionaries to merge 97 :type dicts: Dict[Any, Any] 98 :param factory: the constructor of the mapping type to create (default is `dict`) 99 :type factory: Type 100 :return: a merged dictionary of type {factory} 101 :rtype: Dict[Any, Any] 102 """ 103 104 merged = factory() 105 for dictionary in dicts: 106 merged.update(dictionary) 107 merged.update(kwargs) 108 return merged
Merge all specified dictionaries in {dicts} into a single one. Moreover, {kwargs} will be included. In case duplicate keys exist, the order of passing the dictionaries will determine which values will sustain for the keys. The last updated is carried out using {kwargs}
Parameters
- dicts: the dictionaries to merge
- factory: the constructor of the mapping type to create (default is
dict)
Returns
a merged dictionary of type {factory}
def
ensure_iterable(o, exclude=(<class 'str'>, <class 'bytes'>), factory=<class 'tuple'>):
115def ensure_iterable(o, exclude=(str, bytes), factory=tuple): 116 """ 117 wraps an object {o} into an iterable it is not and iterable. the type of the iterable is specified by {factory} 118 :param o: the object to wrap 119 :param exclude: type list of iterable objects which need wrapping (default is (str, bytes)) 120 :type exclude: Iterable[type] 121 :param factory: the Iterable type in which {o} should be wrapped 122 :type factory: type 123 :rtype: Iterable 124 """ 125 if isinstance(o, collections.abc.Iterable): 126 return o if not isinstance(o, exclude) else _wrap_in_iterable(o, factory=factory) 127 else: 128 return _wrap_in_iterable(o, factory=factory)
wraps an object {o} into an iterable it is not and iterable. the type of the iterable is specified by {factory}
Parameters
- o: the object to wrap
- exclude: type list of iterable objects which need wrapping (default is (str, bytes))
- factory: the Iterable type in which {o} should be wrapped