aegirhall / console-menu

A simple Python menu system for building terminal user interfaces.
MIT License
365 stars 58 forks source link

How can I catch a SIGINT (Ctrl+C) and stop a function called by a FunctionItem? #55

Open thumsl opened 3 years ago

thumsl commented 3 years ago

Title sums it up. I use a menu to start long running functions and would like to stop them catching a CTRL+C. How can I do this?

FelipeEmos commented 3 years ago

This has nothing to do with this module, this is a python question. I recommend you look up into "Exceptions" and "Error Handling", that's what you are looking for. Every time you press CTRL+C python throws a KeyboardInterrupt exception and your program can catch it and treat it itself (instead of leaving for the normal handling python does).

Use my following code inside your "long running functions" and change the "sys.exit()" for your own thing. I also recommend you look up "threading", if you are in the "long running functions" game, than probably you shouldn't run them in the same thread as the UI

import sys, time
var = 1

try:
    while(True):
        var += 0.1
        time.sleep(0.1)
except KeyboardInterrupt:
    print("var = ", var)
    sys.exit()

Here are super useful links:

Have fun!

FelipeEmos commented 3 years ago

Actually, I've tried to do the handling the way I've described to you and it didn't work....

I don't know why, but I suspect the menu application is catching the exception itself. I stopped investigating because I figured out "Ctrl + D" works fine to kill the current thread and get me back to my Main Menu. Maybe it could work for you if you don't have submenus nested as in my application.

jamesfowkes commented 2 years ago

Hi @FelipeEmos I am looking for an answer to the same issue (capturing Ctrl-C inside a FunctionItem function). Ctrl-D did not work. Can you help?

error9900 commented 11 months ago

I think this is related to this, so adding it here, rather than starting a new Issue:

Simplified code to show the issue I ran into:

This will raise a KeyError and cause an exit, as expected:

from consolemenu import ConsoleMenu
from consolemenu.items import FunctionItem

def raise_exception():
    raise KeyError

menu = ConsoleMenu()
function_item = FunctionItem("Raise KeyError", raise_exception)
menu.append_item(function_item)
menu.show()

This will sometimes flash the Exception text in the terminal, but ultimately returns to the menu:

from consolemenu import ConsoleMenu
from consolemenu.items import FunctionItem

def raise_exception():
    raise KeyError

while True:
    menu = ConsoleMenu()
    function_item = FunctionItem("Raise KeyError", raise_exception)
    menu.append_item(function_item)
    menu.show()

To rule out the while loop somehow causing the issue: This will raise a KeyError and cause an exit, as expected:

from consolemenu import ConsoleMenu
from consolemenu.items import FunctionItem

def raise_exception():
    raise KeyError

while True:
    raise_exception()

What led me to this was not being able to catch the exceptions raised from menu.show()...:

This makes it seem like menu.show() is dumping the Exception to the terminal and forcing an exit instead of raising it up to the calling function...:

from consolemenu import ConsoleMenu
from consolemenu.items import FunctionItem

def raise_exception():
    raise KeyError

menu = ConsoleMenu()
function_item = FunctionItem("Raise KeyError", raise_exception)
menu.append_item(function_item)
try:
    menu.show()
except KeyError:
    print("Everything is fine!")