pythonpython-2.7urwid

python urwid timeout on idle


Is there a way to have a urwid app to do a sys.exit() after a configurable timeout if no input has been received from the user in more than 30 seconds?

We are facing network outages and that leads to the SSH Session being dropped but the client program keeps running and holds a Database lock and manually killing is the only option for now and hence this requirement.


Solution

  • You can set an alarm in the main loop that will call whatever code you want when it times out. Here I call a function that uses the ExitMainLoop exception, but sys.exit() would also work.

    This code cancels the previous alarm (if any) when keyboard input happens, then sets a new alarm. As long as keys are coming in, the alarm should never go off.

    Internally, as of late 2020, for alarms urwid seems to use Python's time.time(), which is not guaranteed to only go forward one-second-per-second. The alarm might go off early, exiting the program, if the system clock gets adjusted forward (by NTP?).

    import urwid
    
    timeout_time=30
    
    def urwid_exit(loop, user_data):
        raise urwid.ExitMainLoop
        
    def handle_input(input):
        global txt
        global loop
        
        #don't reset the alarm on a mouse click,  
        #  and don't try to display it (the .set_text would error if given a tuple)
        if not type(input) is tuple:
            if hasattr(handle_input, "last_alarm") and handle_input.last_alarm:
                loop.remove_alarm(handle_input.last_alarm)
            handle_input.last_alarm = loop.set_alarm_in(timeout_time, urwid_exit)
            txt.set_text("key pressed: %s" % input)
    
    txt = urwid.Text("Hello world")
    fill = urwid.Filler(txt, 'top')
    loop = urwid.MainLoop(fill, unhandled_input=handle_input)
    #call handle input once without any input to get the alarm started
    handle_input(None)
    loop.run()