Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Timed Exit
#11
Ok, so I got a little distracted over signal and SIGALRM, and think we should just stop looking at them, since they don't work on Windows. I find it surprising that there isn't a built-in way to handle a timeout on input. I think one way could be to use msvcrt's methods to get one character at a time, as those return immediately if there isn't any keyboard input, but then it would ONLY work on Windows. So I think maybe the "best" way would be to spawn a new thread which tries to get the input, and the main thread will just move on if it takes too long.

The queue has a timeout on it's .get() method, so here, I used that to handle the timeout, and then just ignore the error raised when the queue is empty (it's empty, because the user never typed anything, so nothing was ever put in the queue):
import threading
import queue
import time


def get_input(message, channel):
    response = input(message)
    channel.put(response)


def input_with_timeout(message, timeout):
    channel = queue.Queue()
    message = message + " [{} sec timeout] ".format(timeout)
    thread = threading.Thread(target=get_input, args=(message, channel))
    # by setting this as a daemon thread, python won't wait for it to complete
    thread.daemon = True
    thread.start()

    try:
        response = channel.get(True, timeout)
        return response
    except queue.Empty:
        pass
    return None


if __name__ == "__main__":
    print(input_with_timeout("Commands:", 2))
Reply
#12
Here another option.
from threading import Thread

class Input:
    def __init__(self, message, timeout):
        self.response = None
        print('You have {0} seconds to answer'.format(timeout))
        thread = Thread(target=self.do_input, args=(message,))
        thread.start()
        # wait for a response
        thread.join(timeout)
        # closing input after timeout
        if self.response is None:
            print('\nTimes up. Press enter to continue')
            thread.join()
            # clear response from enter key
            self.response = None

    def do_input(self, message):
        self.response = input(message)

    # optional
    def get(self):
        return self.response

def main():
    r = Input('Type anything >> ', 2).get()
    print(r)
    r = Input('Type anything >> ', 3)
    print(r.response)

main()

Maybe better just use class method.
from threading import Thread

class Input:
    _response = None # internal use only

    @classmethod
    def timeout(cls, message, timeout):
        cls._response = None
        print('You have {0} seconds to answer'.format(timeout))
        thread = Thread(target=cls.do_input, args=(message,))
        thread.start()
        # wait for a response
        thread.join(timeout)
        # closing input after timeout
        if cls._response is None:
            print('\nTimes up. Press enter to continue')
            thread.join()
            # clear response from enter key
            cls._response = None
        return cls._response

    @classmethod
    def do_input(cls, message):
        cls._response = input(message)

def main():
    r = Input.timeout('Type anything >> ', 2)
    print(r)
    r = Input.timeout('Type anything >> ', 3)
    print(r)


main()
99 percent of computer problems exists between chair and keyboard.
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020