def timeout(timeout):

    def decorate(f):
        def timeout_handler(signum, frame):
            raise JobTimeoutException(traceback.format_stack())

        def new_f(*args, **kwargs):
            old_handler = signal.signal(signal.SIGALRM, timeout_handler)
            signal.alarm(timeout)

            result = f(*args, **kwargs)  # f() always returns, in this scheme

            signal.signal(signal.SIGALRM, old_handler)  # Old signal handler is restored
            signal.alarm(0)  # Alarm removed
            return result

        if compat.PY2:
            new_f.func_name = f.func_name
        else:
            new_f.__name__ = f.__name__

        return new_f

    return decorate

# This code really has nothing to do with jobs, just lives here for lack of a better place.
A learner with a low learned tells us more about guess
dataset/ETHPy150Open openaddresses/machine/openaddr/jobs.py/timeout--crossover with--dataset/ETHPy150Open heiskr/sagefy/server/test/test_modules_sequencer_guess_and_slip.py/test_guess_learner