cmd module: capture Ctrl+C [duplicate] - python

This question already has answers here:
How do I capture SIGINT in Python?
(12 answers)
Closed 7 years ago.
I am using Python's default cmd module to create a command-line-based app.
According to the docs CTRL+D (which signals EOF to the command line) can be captured by implementing a function called do_EOF, which works pretty well.
However, is there a way to capture CTRL+C as well? I want to execute a specific function (which saves all unsaved changes) before terminating the Python-script, which is the main motivation for doing this.
Currently, I capture KeyboardInterrupts using a try-except-block like the following:
if __name__ == '__main__':
try:
MyCmd().cmdloop()
except KeyboardInterrupt:
print('\n')
I tried to extend this into:
if __name__ == '__main__':
try:
app = MyCmd().cmdloop()
except KeyboardInterrupt:
app.execute_before_quit()
print('\n')
Which leads to the following NameError:
name 'app' is not defined
How can I capture CTRL+C?
I think signal could somehow do the trick, but I am not sure...
Remark: The script needs to be running on both Unix- and Windows-based systems.

Ctrl C activates system exit which is like an exception, I'm pretty sure you can catch it with try and except. Note: to catch SystemExit you must specify it in the except explicitly.

Related

Python: Timeout Exception Handling with Signal.Alarm

I am trying to implement a timeout exception handler if a function call is taking too long.
EDIT: In fact, I am writing a Python script using subprocess, which calls an old C++ program with arguments. I know that the program hangs from time to time, not returning anything. That's why I am trying to put a time limit and to move on to next call with different argument and etc.
I've been searching and trying to implement it, but it doesn't quite work, so I wish to get some help. What I have so far is:
#! /usr/bin/env python
import signal
class TimeOutException(Exception):
def __init__(self, message, errors):
super(TimeOutException, self).__init__(message)
self.errors = errors
def signal_handler(signum, frame):
raise TimeOutException("Timeout!")
signal.signal(signal.SIGALRM, signal_handler)
signal.alarm(3)
try:
while True:
pass
except TimeOutException:
print "Timed out!"
signal.alarm(0)
EDIT: The Error message I receive currently is "TypeError: init() takes exactly 3 arguments (2 given)
Also, I would like ask a basic question regarding the except block. what's the role difference between the code right below "except TimeOutException" and the code in the "Exception handler"? It seems both can do the same thing?
Any help would be appreciated.
if a function call is taking too long
I realize that this might not be obvious for inexperienced developers, but the methods applicable for approaching this problem entirely depend on what you are doing in this "busy function", such as:
Is this a heavy computation? If yes, which Python interpreter are you using? CPython or PyPy? If CPython: does this computation only use Python bytecode or does it involve function calls outsourced to compiled machine code (which may hold Python's Global Interpreter Lock for quite an uncontrollable amount of time)?
Is this a lot of I/O work? If yes, can you abort this I/O work in an arbitrary state? Or do you need to properly clean up? Are you using a certain framework such as gevent or Twisted?
Edit:
So, it looks you are just spawning a subprocess and wait for it to terminate. Great, that is actually one of the most simple problems to implement a timeout control for. Python (3) ships a corresponding feature! :-) Have a look at
https://docs.python.org/3/library/subprocess.html#subprocess.call
The timeout argument is passed to Popen.wait(). If the timeout
expires, the child process will be killed and then waited for again.
The TimeoutExpired exception will be re-raised after the child process
has terminated.
Edit2:
Example code for you, save this to a file and execute it with Python 3.3, at least:
import subprocess
try:
subprocess.call(['python', '-c', 'print("hello")'], timeout=2)
except subprocess.TimeoutExpired as e:
print("%s was terminated as of timeout. Its output was:\n%s" % (e.cmd, e.output))
try:
subprocess.call(['python'], timeout=2)
except subprocess.TimeoutExpired as e:
print("%s was terminated as of timeout. Its output was:\n%s" % (e.cmd, e.output))
In the first case, the subprocess immediately returns. No timeout exception will be raised. In the second case, the timeout expires, and your controlling process (the process running above's script) will attempt to terminate the subprocess. This succeeds. After that, the subprocess.TimeoutExpired is raised and the exception handler deals with it. For me the output of the script above is ['python'] was terminated as of timeout. Its output was:
None:

Stop Windows from closing Python

This question may have been asked a couple of times but I cannot seem to find it.
Basically I am just learning Python and I am on Windows, this means I double click the .py file and open it. This works great until an error appears, at which point Python calls exit and the window closes.
One way, of course, to get around this is to use the cmd program in Windows and run the Python program from there, however, is there a way to fix it so that my application doesn't bail out and close as soon as it hits an error if I open it from Windows Explorer?
while(True):
try:
number = input('Enter a number: ')
if(is_int(number) is False):
print('Please actually enter a number')
if(number > 0):
answer = input('Oh Noes you really want that?')
if(answer == 'yes'):
sys.exit(0);
except KeyboardInterrupt:
sys.exit(0)
except Exception as e:
input('')
In order to keep your program intact, e.g. to not introduce unwanted catch-em-all exception handling (aka pokemon handling) there are at least three options:
Use any console terminal, e.g. built-in cmd or powershell or any third-party console apps out there.
Use any IDE: pycharm, IDLE (python windows installer by default sets it up) or whatever you have capable of running python code.
Use text editor plugins for running python code. At least notepad++ and sublime text are capable of doing so.
I would recommend starting with option 1 for starters, then slowly move to option 3 for small scripts and projects, and option two for larger ones.
I you put an input function at the bottom of your script then it will hang there until you hit enter or close the command prompt. If you call an exit function put it immediately before the exit function is called. Otherwise place it at the bottom of the script.
Also I assume you have defined is_int already in your script?
What would you think it should do?
Python is drawing the window you see, if python crashes, the windows is going away.
You can run it trough cmd, or within an IDE. (like IDLE, that has some problem though when it comes to GUI)
Otherwise, add something like this at the end of the file
try:
run()
except Exception as inst:
print type(inst), inst.args
#it prints the exception
print sys.exc_traceback.tb_lineno
#if you want the line number where the error occurred in the source code
raw_input()
inst is the exception instance, you can see the type and the list of arguments.
Then with the sys module you can also see the line where the error occurred in the code.
This way every error will be handled and displayed before closing
Is this the right way?
No. You should really be using ad IDE (like Eclipse with PyDev or PyCharm).
After #SeçkinSavaşçı's extremely useful comment at the start:
The most common way is to let it wait for an input, then ignore the input and terminate the script.
Which took me a second to understand I went in search of how to do this, so first I saw to stop the script and used:
while(True):
try:
# Application code here
except:
input('')
Which worked really well to catch all errors, which unlike in PHP (which I have become comfortable with unfortunately) are all exceptions.
So the next part was to to tell me what error had occured and how to fix it, I needed a backtrace. It just so happens that the Python docs gave me the answer right here: http://docs.python.org/2/library/traceback.html#traceback-examples in an easy to see example:
exc_type, exc_value, exc_traceback = sys.exc_info()
print(traceback.print_exception(exc_type, exc_value, exc_traceback, limit=2, file=sys.stdout));
Add that above the input('') and I had my perfect error handling showing me everything I needed.
Thanks all,
Try import time and time.sleep(). Also, I recommend you to use IDLE or Geany. I've been using them and they work out well.

Python ctrl+c, excute function if early termination

I have a python script that creates a lot of temporary files. If the script terminates early because of a ctrl+c interrupt, I would like to quickly delete those files before the program is allowed to end.
What's the pythonic way handling this?
Open the files in a with statement, if possible, or use a try statement with a finally block that closes the files. If you're using tempfile, the files will automatically be destroyed when closed; otherwise, you may need to delete them yourself in the finally block.
http://docs.python.org/2/library/exceptions.html#exceptions.KeyboardInterrupt
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
cleanUp()
Either catch and handle KeyboardInterrupt, or set an exit handler with atexit.
Also, tempfile.

Difference between exit() and sys.exit() in Python

In Python, there are two similarly-named functions, exit() and sys.exit(). What's the difference and when should I use one over the other?
exit is a helper for the interactive shell - sys.exit is intended for use in programs.
The site module (which is imported automatically during startup, except if the -S command-line option is given) adds several constants to the built-in namespace (e.g. exit). They are useful for the interactive interpreter shell and should not be used in programs.
Technically, they do mostly the same: raising SystemExit. sys.exit does so in sysmodule.c:
static PyObject *
sys_exit(PyObject *self, PyObject *args)
{
PyObject *exit_code = 0;
if (!PyArg_UnpackTuple(args, "exit", 0, 1, &exit_code))
return NULL;
/* Raise SystemExit so callers may catch it or clean up. */
PyErr_SetObject(PyExc_SystemExit, exit_code);
return NULL;
}
While exit is defined in site.py and _sitebuiltins.py, respectively.
class Quitter(object):
def __init__(self, name):
self.name = name
def __repr__(self):
return 'Use %s() or %s to exit' % (self.name, eof)
def __call__(self, code=None):
# Shells like IDLE catch the SystemExit, but listen when their
# stdin wrapper is closed.
try:
sys.stdin.close()
except:
pass
raise SystemExit(code)
__builtin__.quit = Quitter('quit')
__builtin__.exit = Quitter('exit')
Note that there is a third exit option, namely os._exit, which exits without calling cleanup handlers, flushing stdio buffers, etc. (and which should normally only be used in the child process after a fork()).
If I use exit() in a code and run it in the shell, it shows a message asking whether I want to kill the program or not. It's really disturbing.
See here
But sys.exit() is better in this case. It closes the program and doesn't create any dialogue box.
Solution, Origins, Differences & Speed
Why do we need the exit() /
sys.exit() commands?
Usually, the code runs through the lines until the end and the program exists automatically.
Occasionally, we would like to ask the program to close before the full cycle run.
An example case is when you implement authentication and a user fails to authenticate, in some cases you would like to exit the program.
The exit()
Exits Python.
Maybe you didn't know this, but it's a synonym of quit() and was added after quit() to make python more user friendly.
Designed to work with interactive shells.
Usage:
Use the built-in exit() out of the box, as is, without importing any library.
Just type this:
exit()
Execution Time: 0.03s
Pros:
Faster to use (built-in)
Works both with python 2.x and python 3.x
Fast
Can be used exactly like sys.exit() (with the exception)
Cons:
No exception message
The sys.exit()
Exits Python and raising the SystemExit exception (requires an import).
Designed to work inside programs.
Usage:
import sys
sys.exit()
Execution Time (of just the import and sys.exit()): 0.07s
Or you can use a message for the SystemExit exception:
Added finally block to illustrate code cleanup clause. Inspired by #Nairum.
import sys
try:
sys.exit("This is an exit!")
except SystemExit as error:
print(error)
finally:
print("Preforming cleanup in 3, 2, 1..")
# Do code cleanup on exit
Output:
This is an exit!
Preforming cleanup in 3, 2, 1..
Pros:
Triggers SystemExit exception
You can use an exception message
Closes without a dialog
Utilizes finally clause of try
Works both with python 2.x and python 3.x
Cons:
Needs an import
Slower by 57.1% than exit()
Conclusion:
If you don't need an exception with an optional message, then use exit(), this is faster and built-in.
If you require more functionality of an exception with an optional message, use sys.exit().
In the code examples I am using Python 3.x

How do I abort the execution of a Python script? [duplicate]

This question already has answers here:
How do I terminate a script?
(14 answers)
Closed 3 years ago.
I have a simple Python script that I want to stop executing if a condition is met.
For example:
done = True
if done:
# quit/stop/exit
else:
# do other stuff
Essentially, I am looking for something that behaves equivalently to the 'return' keyword in the body of a function which allows the flow of the code to exit the function and not execute the remaining code.
To exit a script you can use,
import sys
sys.exit()
You can also provide an exit status value, usually an integer.
import sys
sys.exit(0)
Exits with zero, which is generally interpreted as success. Non-zero codes are usually treated as errors. The default is to exit with zero.
import sys
sys.exit("aa! errors!")
Prints "aa! errors!" and exits with a status code of 1.
There is also an _exit() function in the os module. The sys.exit() function raises a SystemExit exception to exit the program, so try statements and cleanup code can execute. The os._exit() version doesn't do this. It just ends the program without doing any cleanup or flushing output buffers, so it shouldn't normally be used.
The Python docs indicate that os._exit() is the normal way to end a child process created with a call to os.fork(), so it does have a use in certain circumstances.
You could put the body of your script into a function and then you could return from that function.
def main():
done = True
if done:
return
# quit/stop/exit
else:
# do other stuff
if __name__ == "__main__":
#Run as main program
main()
import sys
sys.exit()
You can either use:
import sys
sys.exit(...)
or:
raise SystemExit(...)
The optional parameter can be an exit code or an error message. Both methods are identical. I used to prefer sys.exit, but I've lately switched to raising SystemExit, because it seems to stand out better among the rest of the code (due to the raise keyword).
Try
sys.exit("message")
It is like the perl
die("message")
if this is what you are looking for. It terminates the execution of the script even it is called from an imported module / def /function
exit() should do the trick
exit() should do it.
If the entire program should stop use sys.exit() otherwise just use an empty return.

Categories