Source code for inferno.utils.python_utils

"""Utility functions with no external dependencies."""
import signal
import warnings
import functools
import inspect


[docs]def is_listlike(x): return isinstance(x, (list, tuple))
[docs]def to_iterable(x): return [x] if not is_listlike(x) else x
[docs]def from_iterable(x): return x[0] if (is_listlike(x) and len(x) == 1) else x
[docs]def robust_len(x): return len(x) if is_listlike(x) else 1
[docs]def as_tuple_of_len(x, len_): if is_listlike(x): assert len(x) == len_, \ "Listlike object of len {} can't be returned " \ "as a tuple of length {}.".format(len(x), len_) return tuple(x) else: return (x,) * len_
[docs]def has_callable_attr(object_, name): return hasattr(object_, name) and callable(getattr(object_, name))
[docs]def is_maybe_list_of(check_function): def decorated_function(object_, **kwargs): if isinstance(object_, (list, tuple)): return all([check_function(_object, **kwargs) for _object in object_]) else: return check_function(object_, **kwargs) return decorated_function
[docs]class delayed_keyboard_interrupt(object): """ Delays SIGINT over critical code. Borrowed from: https://stackoverflow.com/questions/842557/ how-to-prevent-a-block-of-code-from-being-interrupted-by-keyboardinterrupt-in-py """ # PEP8: Context manager class in lowercase def __enter__(self): self.signal_received = False self.old_handler = signal.getsignal(signal.SIGINT) signal.signal(signal.SIGINT, self.handler)
[docs] def handler(self, sig, frame): self.signal_received = (sig, frame)
def __exit__(self, type, value, traceback): signal.signal(signal.SIGINT, self.old_handler) if self.signal_received: self.old_handler(*self.signal_received)
[docs]def get_config_for_name(config, name): config_for_name = {} for key, val in config.items(): if isinstance(val, dict) and name in val: # we leave the slicing_config validation to classes higher up in MRO config_for_name.update({key: val.get(name)}) else: config_for_name.update({key: val}) return config_for_name
string_types = (type(b''), type(u''))
[docs]def deprecated(reason): """ This is a decorator which can be used to mark functions as deprecated. It will result in a warning being emitted when the function is used. Borrowed from https://stackoverflow.com/questions/2536307/ decorators-in-the-python-standard-lib-deprecated-specifically by Laurent LAPORTE https://stackoverflow.com/users/1513933/laurent-laporte """ if isinstance(reason, string_types): # The @deprecated is used with a 'reason'. # # .. code-block:: python # # @deprecated("please, use another function") # def old_function(x, y): # pass def decorator(func1): if inspect.isclass(func1): fmt1 = "Call to deprecated class {name} ({reason})." else: fmt1 = "Call to deprecated function {name} ({reason})." @functools.wraps(func1) def new_func1(*args, **kwargs): warnings.simplefilter('always', DeprecationWarning) warnings.warn( fmt1.format(name=func1.__name__, reason=reason), category=DeprecationWarning, stacklevel=2 ) warnings.simplefilter('default', DeprecationWarning) return func1(*args, **kwargs) return new_func1 return decorator elif inspect.isclass(reason) or inspect.isfunction(reason): # The @deprecated is used without any 'reason'. # # .. code-block:: python # # @deprecated # def old_function(x, y): # pass func2 = reason if inspect.isclass(func2): fmt2 = "Call to deprecated class {name}." else: fmt2 = "Call to deprecated function {name}." @functools.wraps(func2) def new_func2(*args, **kwargs): warnings.simplefilter('always', DeprecationWarning) warnings.warn( fmt2.format(name=func2.__name__), category=DeprecationWarning, stacklevel=2 ) warnings.simplefilter('default', DeprecationWarning) return func2(*args, **kwargs) return new_func2 else: raise TypeError(repr(type(reason)))