Python cancel raw_input/input via writing to stdin?
Asked Answered
C

1

5

For starters, I'm on python 2.7.5 and Windows x64, my app is targeted at those parameters.

I'm in need of a way to cancel a raw_input after a certain amount of time has passed. Currently I have my main thread starting two child threads, one is the timer (threading.Timer) and the other fires the raw_input. These both return a value to a Queue.queue that the main thread monitors. It then acts on what is sent to the queue.

# snip...
q = Queue.queue()
# spawn user thread
user = threading.Thread(target=user_input, args=[q])
# spawn timer thread (20 minutes)
timer = threading.Timer(1200, q.put, ['y'])
# wait until we get a response from either
while q.empty():
    time.sleep(1)
timer.cancel()

# stop the user input thread here if it's still going

# process the queue value
i = q.get()
if i in 'yY':
    # do yes stuff here
elif i in 'nN':
    # do no stuff here

# ...snip

def user_input(q):
    i = raw_input(
        "Unable to connect in last {} tries, "
        "do you wish to continue trying to "
        "reconnect? (y/n)".format(connect_retries))
    q.put(i)

The research that I've done so far seems to say that it's not possible to "correctly" cancel a thread. I feel that processes are too heavy for the task, though I'm not opposed to using them if that's what really needs to be done. Instead, my thought is that if the timer finishes with no user input, I can write a value to stdin and close that thread gracefully.

So, how do I write to stdin from the main thread so that the child thread accepts the input and closes gracefully? Thanks!

Colorless answered 18/10, 2013 at 17:10 Comment(0)
D
11

You can use the threading.Thread.join method to handle the timeout. The key to getting it working is to set the daemon attribute as shown below.

import threading

response = None
def get_response():
    global response
    response = input("Do you wish to reconnect? ")

thread = threading.Thread(target=get_response, daemon=True)
thread.start()
thread.join(2)
if response is None:
    print()
    print('Exiting')
else:
    print('As you wish')
Dachy answered 18/10, 2013 at 17:34 Comment(2)
I do believe that will work as in my case (a CLI program), I won't care if the main thread blocks while we're waiting for input. Thanks!Colorless
Amazing. This is the only example that actually performs a proper timeout of input (for Python 3), without having to press Enter key again to have the code continue to run.Whitson

© 2022 - 2024 — McMap. All rights reserved.