Source code for pygaps.utilities.python_utilities
"""Collections of various python utilities."""
import importlib
import sys
import warnings
from collections import abc
def _one_pass(iters):
i = 0
while i < len(iters):
try:
yield next(iters[i])
except StopIteration:
del iters[i]
else:
i += 1
[docs]def zip_varlen(*iterables):
"""Variable length zip() function."""
iters = [iter(it) for it in iterables]
while True: # broken when an empty tuple is given by _one_pass
val = tuple(_one_pass(iters))
if val:
yield val
else:
break
[docs]def grouped(iterable, n):
"""Divide an iterable in subgroups of max n elements."""
return zip_varlen(*[iter(iterable)] * n)
[docs]def deep_merge(a, b, path=None, update=True):
"""Recursive updates of a dictionary."""
if path is None:
path = []
for key, val in b.items():
if key in a:
if (isinstance(a[key], abc.Mapping) and isinstance(val, abc.Mapping)):
deep_merge(a[key], val, path + [str(key)], update)
elif a[key] == val:
pass # same leaf value
elif update:
a[key] = val
else:
raise Exception(f"Conflict at {'.'.join(path + [str(key)])}")
else:
a[key] = val
return a
[docs]class SimpleWarning():
"""
Context manager overrides warning formatter to remove unneeded info.
"""
old_formatter = None
def __enter__(self):
# ignore everything except the message
def custom_formatwarning(msg, *args, **kwargs):
return str(msg) + '\n'
self.old_formatter = warnings.formatwarning
warnings.formatwarning = custom_formatwarning
return True
def __exit__(self, typ, value, traceback):
warnings.formatwarning = self.old_formatter
return True
def _load_lazy(fullname):
"""
This lazy load was used for non-critical modules to speed import time.
Examples: matplotlib, scipy.optimize.
However it tends to destroy the import system. Do not use.
"""
try:
return sys.modules[fullname]
except KeyError as err:
spec = importlib.util.find_spec(fullname)
if not spec:
raise ModuleNotFoundError(f"Could not import {fullname}.") from err
loader = importlib.util.LazyLoader(spec.loader)
module = importlib.util.module_from_spec(spec)
# Make module with proper locking and get it inserted into sys.modules.
loader.exec_module(module)
sys.modules[fullname] = module
return module