Need function like "raw_input", but with time limit

R

Radioactive Man

anyone know of a function like "raw_input", which collects a string
from the user entry, but one where I can set a time limit, as follows:

time_limit = 10 # seconds
user_answer = function_xyz("GIVE ME AN ANSWER: ", time_limit)


The problem with "raw_input" is that it will stop unattended script
indefinitely. I'm looking for a function that does the exact same
thing, but with a time limit feature, and preferably one that returns
an empty string ('') when it gets no response. Any suggestions?
 
A

Alex Martelli

Radioactive Man said:
anyone know of a function like "raw_input", which collects a string
from the user entry, but one where I can set a time limit, as follows:

time_limit = 10 # seconds
user_answer = function_xyz("GIVE ME AN ANSWER: ", time_limit)


The problem with "raw_input" is that it will stop unattended script
indefinitely. I'm looking for a function that does the exact same
thing, but with a time limit feature, and preferably one that returns
an empty string ('') when it gets no response. Any suggestions?

It depends on what platforms you need to run on. On any kind of
Unix-like platform (including Linux, BSD, MacOSX, ...), the function
select of module select can work on any kind of files, including
sys.stdin, and it does provide timeout functionality, too. So, you
could sys.stdout.write the prompt, then call select.select with
sys.stdin.fileno as the only file descriptor of interest and whatever
timeout you wish. Depending on what select.select returns you can then
either sys.stdin.readline (and strip the trailing \n) or just return the
empty string from your function.

Unfortunately, on Windows, select.select works only on sockets, not
ordinary files nor the console. So, if you want to run on Windows, you
need a different approach. On Windows only, the Python standard library
has a small module named msvcrt, including functions such as
msvcrt.kbhit which tells you whether any keystroke is waiting to be
read. Here, you might sys.stdout.write the prompt, then enter a small
loop (including a time.sleep(0.2) or so) which waits to see whether the
user is pressing any key -- if so then you can sys.stdin.readline etc,
but if after your desired timeout is over no key has been hit, then just
return the empty string from your function.

All of this assumes that if the user has STARTED typing something then
you want to wait indefinitely (not timeout in the middle of their
entering their answer!). Otherwise, you have more work to do, since you
must ensure that the user has hit a Return (which means you must peek at
exactly what's in sys.stdin, resp. use msvcrt.getch, one character at a
time). Fortunately, the slightly simpler approach of waiting
indefinitely if the user has started entering seems to be the preferable
one from a user interface viewpoint -- it lets you deal with unattended
consoles as you desire, yet IF the user is around at all it gives the
user all the time they want to COMPLETE their answer.


Alex
 
F

Fredrik Lundh

Radioactive Man said:
anyone know of a function like "raw_input", which collects a string
from the user entry, but one where I can set a time limit, as follows:

time_limit = 10 # seconds
user_answer = function_xyz("GIVE ME AN ANSWER: ", time_limit)

this works on some platforms:

import signal, sys

def alarm_handler(*args):
raise Exception("timeout")

def function_xyz(prompt, timeout):
signal.signal(signal.SIGALRM, alarm_handler)
signal.alarm(timeout)
sys.stdout.write(prompt)
sys.stdout.flush()
try:
text = sys.stdin.readline()
except:
text = ""
signal.alarm(0)
return text

</F>
 
R

Radioactive Man

It depends on what platforms you need to run on. On any kind of
Unix-like platform (including Linux, BSD, MacOSX, ...), the function
select of module select can work on any kind of files, including
sys.stdin, and it does provide timeout functionality, too. So, you
could sys.stdout.write the prompt, then call select.select with
sys.stdin.fileno as the only file descriptor of interest and whatever
timeout you wish. Depending on what select.select returns you can then
either sys.stdin.readline (and strip the trailing \n) or just return the
empty string from your function.

Unfortunately, on Windows, select.select works only on sockets, not
ordinary files nor the console. So, if you want to run on Windows, you
need a different approach. On Windows only, the Python standard library
has a small module named msvcrt, including functions such as
msvcrt.kbhit which tells you whether any keystroke is waiting to be
read. Here, you might sys.stdout.write the prompt, then enter a small
loop (including a time.sleep(0.2) or so) which waits to see whether the
user is pressing any key -- if so then you can sys.stdin.readline etc,
but if after your desired timeout is over no key has been hit, then just
return the empty string from your function.

In other words, the user must make any entries while the time.sleep()
statement is running. If the user has entered data during this time,
it should be indicated by the value of msvcrt.kbhit(). The problem
I've had is that msvcrt.kbhit() returns 0 no matter what I've entered
before the statement is executed and while the sleep statement is
being executed.
All of this assumes that if the user has STARTED typing something then
you want to wait indefinitely (not timeout in the middle of their
entering their answer!). Otherwise, you have more work to do, since you
must ensure that the user has hit a Return (which means you must peek at
exactly what's in sys.stdin, resp. use msvcrt.getch, one character at a
time). Fortunately, the slightly simpler approach of waiting
indefinitely if the user has started entering seems to be the preferable
one from a user interface viewpoint -- it lets you deal with unattended
consoles as you desire, yet IF the user is around at all it gives the
user all the time they want to COMPLETE their answer.


Alex


Thanks for the info.
 
R

Radioactive Man

this works on some platforms:

import signal, sys

def alarm_handler(*args):
raise Exception("timeout")

def function_xyz(prompt, timeout):
signal.signal(signal.SIGALRM, alarm_handler)
signal.alarm(timeout)
sys.stdout.write(prompt)
sys.stdout.flush()
try:
text = sys.stdin.readline()
except:
text = ""
signal.alarm(0)
return text

</F>

Is that for a Unix system? I am running windows 95 and/or XP and my
signal.signal module does not have a "SIGALRM" attribute. Thus, I get
an error message when I try to run that script.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top