1

I'm writing a small, single function that is designed to request user input with a time delay. When the time delay runs out, the function should return None instead of a user's response and then should continue with the rest of the script.

In the current implementation, the user input works and the timeout works, with the timeout message printed by a signal handler function which is defined within the function (I'm aiming to have this outer function fairly self-contained). However, processing then halts (rather than exiting the while loop defined in the main function) and I'm not sure why.

How can I get processing to continue? Am I misusing signal in some way? Could a lambda be used in place of an explicitly-defined function for the handler function?

#!/usr/bin/env python

from __future__ import print_function
import signal

import propyte

def main():

    response = "yes"
    while response is not None:
        response = get_input_nonblocking(
            prompt  = "ohai? ",
            timeout = 5
        )
    print("start non-response procedures")
    # do things

def get_input_nonblocking(
    prompt          = "",
    timeout         = 5,
    message_timeout = "prompt timeout"
    ):
    def timeout_manager(signum, frame):
        print(message_timeout)
    #signal.signal(signal.SIGALRM, lambda: print(message_timeout))
    signal.signal(signal.SIGALRM, timeout_manager)
    signal.alarm(timeout)
    try:
        response = propyte.get_input(prompt)
        return response
    except:
        return None

if __name__ == '__main__':
    main()
d3pd
  • 7,935
  • 24
  • 76
  • 127

1 Answers1

3

What you've got is almost there, but you need to raise an exception inside your signal handler. raw_input will block until something happens, either input or an exception. If you raise an exception in the signal handler, that will then interrupt raw_input and execution will fall into the except in your get_input_non_blocking function. Here's a toy example.

import signal
def timeout(signum, frame):
    raise IOError("bye!")

signal.signal(signal.SIGALRM, timeout)
def input():
    try:
            print("omgplz: ")
            return raw_input()
    except IOError:
            return None

signal.alarm(5)
txt = input()
signal.alarm(0)
print(txt)

There's some more discussion and an alternative approach using select in this answer here: Keyboard input with timeout in Python

Hope that helps!

Community
  • 1
  • 1
Seabass
  • 372
  • 1
  • 6