# Path: clustertools/util.py
# def reorder(ls, indices, in_place=False):
#     if in_place:
#         tmps = [ls[i] for i in indices]
#         for i, idx in enumerate(tmps):
#             ls[i] = idx
#         res = ls
# 
#     else:
#         res = copy(ls)
#         for i, idx in enumerate(indices):
#             res[i] = ls[idx]
#     try:
#         return res[:len(indices)]
#     except:
#         return res
# 
# def escape(s):
#     return s.replace("'", "\\\'").replace('"', '\\\"').replace(" ", "\\ ")\
#         .replace("(", "\\(").replace(")", "\\)")
# 
# class SigHandler(object):
#     """
#     Constructor parameter
#     ---------------------
#     callback: callable(exception) -> None
#         The callback to handle signal
#     """
#     def __init__(self, callback):
#         self.callback = callback
#         self.backups = {
#             signal.SIGINT: signal.getsignal(signal.SIGINT),
#             signal.SIGTERM: signal.getsignal(signal.SIGTERM)
#         }
# 
#     def _callback(self, signalnum, frame):
#         exception = SignalExecption(signalnum,
#                                     "Got signal {} in frame "
#                                     "{}".format(signalnum,
#                                                 repr(frame)))
#         self.callback(exception)
#         self._restore()
#         os.kill(os.getpid(), signalnum)
# 
#     def _restore(self):
#         for sig_num, handler in self.backups.items():
#             try:
#                 signal.signal(sig_num, handler)
#             except ValueError:
#                 # ValueError is raised if signal.signal(...) is not called
#                 # from the main thread
#                 pass
# 
#     def __enter__(self):
#         self.backups = {s: signal.getsignal(s) for s in self.backups}
# 
#         for sig_num in self.backups:
#             try:
#                 signal.signal(sig_num, self._callback)
#             except ValueError:
#                 # ValueError is raised if signal.signal(...) is not called
#                 # from the main thread
#                 pass
#         return self
# 
#     def __exit__(self, exc_type, exc_val, exc_tb):
#         if isinstance(exc_val, KeyboardInterrupt) or \
#                 isinstance(exc_val, SystemExit):
#             # KeyboardInterrupt cannot be raised through a SIGINT since its
#             # handler has been modified
#             self.callback(exc_val)
# 
#         self._restore()
# 
# class SignalExecption(RuntimeError):
#     def __init__(self, sig_num, *args, **kwargs):
#         super().__init__(*args, **kwargs)
#         self.sig_num = sig_num
# 
# def call_with(function, dictionary, **kwargs):
#     """
#     Computes the intersection between the function's parameters and
#     the given dictionary
#     Parameters
#     ----------
#     function : callable
#         The function to process
#     dictionary : dict
#         The dictionary to process
#     args : list
#         The list of positional arguments
#     kwargs : dict
#         The keyword arguments
#     Return
#     ------
#     intersect_dict : dict
#         The intersection between the function's parameters and the given
#         dictionary
#     """
#     parameters = inspect.signature(function).parameters
#     d = {k: v for k, v in dictionary.items()}
#     d.update(**kwargs)
# 
#     if inspect.Parameter.VAR_KEYWORD in [x.kind for x in
#                                          list(parameters.values())]:
#         # If function as a **kwargs, it will swallow all the extra arguments
#         return function(**d)
# 
#     return function(**{k: v for k, v in d.items() if k in parameters})
# 
# def hashlist(ls):
#     return sha256(str(ls).encode("utf-8")).digest()
# 
# def deprecated(func):
#     """This is a decorator which can be used to mark functions
#     as deprecated. It will result in a warning being emmitted
#     when the function is used."""
# 
#     @functools.wraps(func)
#     def new_func(*args, **kwargs):
#         warnings.simplefilter('always', DeprecationWarning)  # turn off filter
#         warnings.warn("Call to deprecated function {}.".format(func.__name__),
#                       category=DeprecationWarning, stacklevel=2)
#         warnings.simplefilter('default', DeprecationWarning)  # reset filter
#         return func(*args, **kwargs)
# 
#     return new_func
# 
# def sort_per_type(l):
#     """Sort list l by sorting independtly elements of different types."""
#     per_type = dict()
#     for item in l:
#         class_name = item.__class__.__name__
#         per_type[class_name] = per_type.get(class_name, []) + [item]
#     for class_name, class_list in per_type.items():
#         if class_name != "NoneType":
#             class_list.sort()
#     # sort keys to have a reproducible order for contactenated items
#     sorted_keys = sorted(list(per_type.keys()))
#     return reduce(lambda l1, l2: l1 + l2, [per_type[k] for k in sorted_keys])


import os
import signal
import time
from nose.tools import assert_equal, assert_not_equal
from nose.tools import assert_raises
from nose.tools import assert_true
from clustertools.util import reorder, escape, SigHandler, SignalExecption, \
    call_with, hashlist, deprecated, sort_per_type

class SignalCallback(object):

    def __init__(self):
        self.keyboard_interrupt = False
        self.system_exit = False
        self.sig_num = -1

    def callback(self, exception):
        print(exception)
        if isinstance(exception, SignalExecption):
            self.sig_num = exception.sig_num
        if isinstance(exception, KeyboardInterrupt):
            self.keyboard_interrupt = True
        if isinstance(exception, SystemExit):
            self.system_exit = True


def test_sig_handler():
    # Keyboard interrupt
    def key_interrupt(signal_callback):
        with SigHandler(signal_callback.callback):
            raise KeyboardInterrupt()

    sc = SignalCallback()
    assert_raises(KeyboardInterrupt, key_interrupt, signal_callback=sc)
    assert_true(sc.keyboard_interrupt)

    # System exit
    def sys_exit(signal_callback):

# Path: clustertools/util.py
# def reorder(ls, indices, in_place=False):
#     if in_place:
#         tmps = [ls[i] for i in indices]
#         for i, idx in enumerate(tmps):
#             ls[i] = idx
#         res = ls
# 
#     else:
#         res = copy(ls)
#         for i, idx in enumerate(indices):
#             res[i] = ls[idx]
#     try:
#         return res[:len(indices)]
#     except:
#         return res
# 
# def escape(s):
#     return s.replace("'", "\\\'").replace('"', '\\\"').replace(" ", "\\ ")\
#         .replace("(", "\\(").replace(")", "\\)")
# 
# class SigHandler(object):
#     """
#     Constructor parameter
#     ---------------------
#     callback: callable(exception) -> None
#         The callback to handle signal
#     """
#     def __init__(self, callback):
#         self.callback = callback
#         self.backups = {
#             signal.SIGINT: signal.getsignal(signal.SIGINT),
#             signal.SIGTERM: signal.getsignal(signal.SIGTERM)
#         }
# 
#     def _callback(self, signalnum, frame):
#         exception = SignalExecption(signalnum,
#                                     "Got signal {} in frame "
#                                     "{}".format(signalnum,
#                                                 repr(frame)))
#         self.callback(exception)
#         self._restore()
#         os.kill(os.getpid(), signalnum)
# 
#     def _restore(self):
#         for sig_num, handler in self.backups.items():
#             try:
#                 signal.signal(sig_num, handler)
#             except ValueError:
#                 # ValueError is raised if signal.signal(...) is not called
#                 # from the main thread
#                 pass
# 
#     def __enter__(self):
#         self.backups = {s: signal.getsignal(s) for s in self.backups}
# 
#         for sig_num in self.backups:
#             try:
#                 signal.signal(sig_num, self._callback)
#             except ValueError:
#                 # ValueError is raised if signal.signal(...) is not called
#                 # from the main thread
#                 pass
#         return self
# 
#     def __exit__(self, exc_type, exc_val, exc_tb):
#         if isinstance(exc_val, KeyboardInterrupt) or \
#                 isinstance(exc_val, SystemExit):
#             # KeyboardInterrupt cannot be raised through a SIGINT since its
#             # handler has been modified
#             self.callback(exc_val)
# 
#         self._restore()
# 
# class SignalExecption(RuntimeError):
#     def __init__(self, sig_num, *args, **kwargs):
#         super().__init__(*args, **kwargs)
#         self.sig_num = sig_num
# 
# def call_with(function, dictionary, **kwargs):
#     """
#     Computes the intersection between the function's parameters and
#     the given dictionary
#     Parameters
#     ----------
#     function : callable
#         The function to process
#     dictionary : dict
#         The dictionary to process
#     args : list
#         The list of positional arguments
#     kwargs : dict
#         The keyword arguments
#     Return
#     ------
#     intersect_dict : dict
#         The intersection between the function's parameters and the given
#         dictionary
#     """
#     parameters = inspect.signature(function).parameters
#     d = {k: v for k, v in dictionary.items()}
#     d.update(**kwargs)
# 
#     if inspect.Parameter.VAR_KEYWORD in [x.kind for x in
#                                          list(parameters.values())]:
#         # If function as a **kwargs, it will swallow all the extra arguments
#         return function(**d)
# 
#     return function(**{k: v for k, v in d.items() if k in parameters})
# 
# def hashlist(ls):
#     return sha256(str(ls).encode("utf-8")).digest()
# 
# def deprecated(func):
#     """This is a decorator which can be used to mark functions
#     as deprecated. It will result in a warning being emmitted
#     when the function is used."""
# 
#     @functools.wraps(func)
#     def new_func(*args, **kwargs):
#         warnings.simplefilter('always', DeprecationWarning)  # turn off filter
#         warnings.warn("Call to deprecated function {}.".format(func.__name__),
#                       category=DeprecationWarning, stacklevel=2)
#         warnings.simplefilter('default', DeprecationWarning)  # reset filter
#         return func(*args, **kwargs)
# 
#     return new_func
# 
# def sort_per_type(l):
#     """Sort list l by sorting independtly elements of different types."""
#     per_type = dict()
#     for item in l:
#         class_name = item.__class__.__name__
#         per_type[class_name] = per_type.get(class_name, []) + [item]
#     for class_name, class_list in per_type.items():
#         if class_name != "NoneType":
#             class_list.sort()
#     # sort keys to have a reproducible order for contactenated items
#     sorted_keys = sorted(list(per_type.keys()))
#     return reduce(lambda l1, l2: l1 + l2, [per_type[k] for k in sorted_keys])


# Path: clustertools/test/test_util.py
import os
import signal
import time
from nose.tools import assert_equal, assert_not_equal
from nose.tools import assert_raises
from nose.tools import assert_true
from clustertools.util import reorder, escape, SigHandler, SignalExecption, \
    call_with, hashlist, deprecated, sort_per_type


class SignalCallback(object):

    def __init__(self):
        self.keyboard_interrupt = False
        self.system_exit = False
        self.sig_num = -1

    def callback(self, exception):
        print(exception)
        if isinstance(exception, SignalExecption):
            self.sig_num = exception.sig_num
        if isinstance(exception, KeyboardInterrupt):
            self.keyboard_interrupt = True
        if isinstance(exception, SystemExit):
            self.system_exit = True


def test_sig_handler():
    # Keyboard interrupt
    def key_interrupt(signal_callback):
        with SigHandler(signal_callback.callback):
            raise KeyboardInterrupt()

    sc = SignalCallback()
    assert_raises(KeyboardInterrupt, key_interrupt, signal_callback=sc)
    assert_true(sc.keyboard_interrupt)

    # System exit
    def sys_exit(signal_callback):

        with SigHandler(signal_callback.callback):