python 空闲时 urwid 超时
python urwid timeout on idle
如果超过 30 秒没有收到用户的输入,有没有办法让 urwid 应用程序在可配置的超时后执行 sys.exit()?
我们正面临网络中断,这导致 SSH 会话被删除,但客户端程序保持 运行 并持有数据库锁,手动终止是目前唯一的选择,因此有此要求。
您可以在主循环中设置一个警报,当它超时时将调用您想要的任何代码。在这里,我调用了一个使用 ExitMainLoop 异常的函数,但 sys.exit()
也可以。
这段代码在键盘输入发生时取消之前的报警(如果有的话),然后设置一个新的报警。只要有钥匙进来,警报就永远不会响。
在内部,截至 2020 年底,对于警报,urwid 似乎使用 Python 的 time.time()
,但不能保证每秒只前进一秒。如果系统时钟向前调整(通过 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()
StephenK 的答案略有不同,即使用 loop.event_loop.enter_idle(callback)
而不是 unhandled_input
。每当 urwid 进入空闲状态时,callback
函数将是 运行,包括在处理按键事件之后。这有点更一般:计时器在 all activity 完成后启动。 (比如说,最后一次按键启动了一个需要很多秒才能完成的动作)
相关文档位于
https://urwid.readthedocs.io/en/latest/reference/main_loop.html
import urwid
timeout = 10
txt = urwid.Text(
'This program will exit after '
f'_{timeout}_ seconds of inactivity '
'(no keypresses, etc)\n',
align='center'
)
fill = urwid.Filler(txt, 'top')
loop = urwid.MainLoop(fill)
alarm_handle = None
def alarm_callback(_loop, _user_data):
raise urwid.ExitMainLoop
def idle_callback():
global alarm_handle
loop.remove_alarm(alarm_handle) # remove old alarm
alarm_handle = loop.set_alarm_in(timeout, alarm_callback)
text = txt.get_text()[0] + f"\nAlarm has been reset _{alarm_handle[1]}_ times"
txt.set_text(text)
loop.event_loop.enter_idle(idle_callback)
loop.run()
如果超过 30 秒没有收到用户的输入,有没有办法让 urwid 应用程序在可配置的超时后执行 sys.exit()?
我们正面临网络中断,这导致 SSH 会话被删除,但客户端程序保持 运行 并持有数据库锁,手动终止是目前唯一的选择,因此有此要求。
您可以在主循环中设置一个警报,当它超时时将调用您想要的任何代码。在这里,我调用了一个使用 ExitMainLoop 异常的函数,但 sys.exit()
也可以。
这段代码在键盘输入发生时取消之前的报警(如果有的话),然后设置一个新的报警。只要有钥匙进来,警报就永远不会响。
在内部,截至 2020 年底,对于警报,urwid 似乎使用 Python 的 time.time()
,但不能保证每秒只前进一秒。如果系统时钟向前调整(通过 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()
StephenK 的答案略有不同,即使用 loop.event_loop.enter_idle(callback)
而不是 unhandled_input
。每当 urwid 进入空闲状态时,callback
函数将是 运行,包括在处理按键事件之后。这有点更一般:计时器在 all activity 完成后启动。 (比如说,最后一次按键启动了一个需要很多秒才能完成的动作)
相关文档位于 https://urwid.readthedocs.io/en/latest/reference/main_loop.html
import urwid
timeout = 10
txt = urwid.Text(
'This program will exit after '
f'_{timeout}_ seconds of inactivity '
'(no keypresses, etc)\n',
align='center'
)
fill = urwid.Filler(txt, 'top')
loop = urwid.MainLoop(fill)
alarm_handle = None
def alarm_callback(_loop, _user_data):
raise urwid.ExitMainLoop
def idle_callback():
global alarm_handle
loop.remove_alarm(alarm_handle) # remove old alarm
alarm_handle = loop.set_alarm_in(timeout, alarm_callback)
text = txt.get_text()[0] + f"\nAlarm has been reset _{alarm_handle[1]}_ times"
txt.set_text(text)
loop.event_loop.enter_idle(idle_callback)
loop.run()