Python Forum

Full Version: Timed Exit
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2
Hello, I am making a Python game where there is a sequence of letters, and you have to guess it right within a certain amount of time. However, once the player pushes enter, the code is reviewed. Unless, of course, the time runs out, in which case it just passes. Here is my current code:

now = time.time()
        limit = now + 15
        while time.time() < limit:
            r2 = raw_input("Commands:")
            pass
        word2 = 'sddddwwdddx'
        for i in range(min(len(r2), len(word2))):
            if r2[i] != word2[i]:
                errors += 1
        if errorlevel >= errors or errors == 0:
            print"Your plane sucsessfully went through the course!"
        else:
            pass
However, the person could not press enter until the time is up, but since they don't know when time is up, they have to wait much longer. How could I make it so when you press enter, it exits out of the while loop, but also immediately ends the person's choice if the time is up?

Thank You.
If seen this question one time before. The solution was a trick.
You can use signaling to enforce calling some function and
finally this function raises an TimeoutError which bubbles up.
The minimal implementation as a context manager:

class TimeOut:
    def __init__(self, timeout):
        self.timeout = timeout
        self._orig_handler = signal.signal(signal.SIGALRM, self._timeout)
    def __enter__(self):
        signal.alarm(self.timeout)
        return self
    def __exit__(self, *args):
        signal.signal(signal.SIGALRM, self._orig_handler)
    def _timeout(self, *args):
        raise TimeoutError
Using the context manager:
with TimeOut(5):
    input('Answer in 5 seconds: ')
Error:
--------------------------------------------------------------------------- TimeoutError Traceback (most recent call last) <ipython-input-38-304f3fa31b18> in <module>() 1 with TimeOut(5): ----> 2 input('Answer in 5 seconds: ') 3 <ipython-input-32-8635f61b6ed0> in _timeout(self, *args) 9 signal.signal(signal.SIGALRM, self._orig_handler) 10 def _timeout(self, *args): ---> 11 raise TimeoutError 12 TimeoutError:
Now you have to catch the TimoutError Exception, which bubbles up:
with TimeOut(5):
    try:
        input('Answer in 5 seconds: ')
    except TimeoutError:
        print('\nTime is up!')
Output:
Answer in 5 seconds: Time is up!
What is the final code then?
When I run
class TimeOut:
    def __init__(self, timeout):
        self.timeout = timeout
        self._orig_handler = signal.signal(signal.SIGALRM, self._timeout)
    def __enter__(self):
        signal.alarm(self.timeout)
        return self
    def __exit__(self, *args):
        signal.signal(signal.SIGALRM, self._orig_handler)
    def _timeout(self, *args):
        raise TimeoutError

with TimeOut(5):
    try:
        input('Answer in 5 seconds: ')
    except TimeoutError:
        print('\nTime is up!')
I get:

Error:
Traceback (most recent call last): File "Untitled", line 13 with TimeOut(5): File "Untitled", line 4, in __init__ self._orig_handler = signal.signal(signal.SIGALRM, self._timeout) NameError: global name 'signal' is not defined
You have to import signal. It's in the stdlib of python.

import signal

# your code
Even still, I got this error:
Error:
Traceback (most recent call last): File "Untitled", line 15 with TimeOut(5): File "Untitled", line 6, in __init__ self._orig_handler = signal.signal(signal.SIGALRM, self._timeout) AttributeError: 'module' object has no attribute 'SIGALRM'
Please show your code. Or double check that you didn't name any of your files signal.py, which would override the builtin module.

Per the docs, that should work:
https://docs.python.org/3/library/signal.html#example Wrote:
import signal, os

def handler(signum, frame):
    print('Signal handler called with signal', signum)
    raise OSError("Couldn't open device!")

# Set the signal handler and a 5-second alarm
signal.signal(signal.SIGALRM, handler)
signal.alarm(5)

# This open() may hang indefinitely
fd = os.open('/dev/ttyS0', os.O_RDWR)

signal.alarm(0)          # Disable the alarm
I do not have any docs named signal.py

Code:
import signal
class TimeOut:
    def __init__(self, timeout):
        self.timeout = timeout
        self._orig_handler = signal.signal(signal.SIGALRM, self._timeout)
    def __enter__(self):
        signal.alarm(self.timeout)
        return self
    def __exit__(self, *args):
        signal.signal(signal.SIGALRM, self._orig_handler)
    def _timeout(self, *args):
        raise TimeoutError
 
with TimeOut(5):
    try:
        input('Answer in 5 seconds: ')
    except TimeoutError:
        print('\nTime is up!')
Are you on Windows? SIGALRM only exists on Unix.
Yes, Windows does not have it.
There is also a solution with a Thread: https://stackoverflow.com/a/37648512/2817354

It looks a bit hackish.
He is using a Timer from threading to send the MainThread a KeyboardInterrupt.
I am using Windows 8.1
Since I don't have SIGALRM, what should I do? Is there a Windows equivalent?

Thank You.
Pages: 1 2