I exit() a script but it does NOT exit - python

I try to exit a script but it doesn't exit.
Here is my code:
import sys
try:
...
print "I'm gonna die!"
sys.exit()
except:
...
print 'Still alive!'
And the results are:
I'm gonna die!
Still alive!
WHY?

You are catching the SystemExit exception with your blanket except clause. Don't do that. Always specify what exceptions you are expecting to avoid exactly these things.

If you really need to exit immediately, and want to skip normal exit processing, then you can use os._exit(status). But, as others have said, it's generally much better to exit using the normal path, and just not catch the SystemExit exception. And while we're on the topic, KeyboardInterrupt is another exception that you may not want to catch. (Using except Exception will not catch either SystemExit or KeyboardInterrupt.)

sys.exit() is implemented by raising the SystemExit exception, so cleanup actions specified by finally, except clauses of try statements are honored, and it is possible to intercept the exit attempt at an outer level.
In your example SystemExit is catched by the following except statement.

Related

exit(1) in signal handler just gets caught as SystemExit as there is nothing to it

I have an application that looks like this:
while True:
try:
self.try_to_read_usb_device()
break
except:
time.sleep(1)
I also have an SIGALRM handler which is supposed to exit the program in case it got stuck somewhere:
def alarm_signal_handler(signal, frame):
# Something went wrong
exit(1)
However the exit(1) just get caught by the try/except and gets discarded as this is what that specific except does.
This is quite unexpected to me.
In the complete application there will be a lot of try/except and I don't see myself adding
except SystemExit:
exit(1)
or something for all of them.
Any idea how I should handle that use-case?
The dirty way
You can use os._exit instead of sys.exit.
Note that this has obvious drawbacks exactly because it won't go through an exception:
Exit the process with status n, without calling cleanup handlers, flushing stdio buffers, etc.
The proper way
I'd recommend to instead change your exception handling to catch only things inheriting from Exception, because SystemExit doesn't inherit from Exception for precisely this reason, so it won't be caught accidentally:
except Exception:
See also the SystemExit documentation:
This exception is raised by the sys.exit() function. It inherits from BaseException instead of Exception so that it is not accidentally caught by code that catches Exception. This allows the exception to properly propagate up and cause the interpreter to exit.
This also applies to KeyboardInterrupt by the way - Ctrl+C will be caught by except: but not by except Exception:.
It's illustrated pretty well in the exception hierarchy diagram in the Python docs, which you can find here.

How does an exception know if it's being handled?

When raised, SystemExit causes the interpreter to exit, unless the exception is handled.
try:
raise SystemExit()
except SystemExit:
print('not today')
# Continue flow...
I want to mimic that behavior and write my own exception which executes some code only if the exception isn't caught.
Obviously this wouldn't work:
class MyFatalError(Exception):
def __init__(self):
import sys
sys.exit()
try:
raise MyFatalError()
except MyFatalError:
print('never gets here')
(...because an __init__ executes on instantiation, regardless of whether the error is handled.)
Is there a (straightforward and pythonic) way to make an exception behave differently when being handled?
You should not be thinking of SystemExit as a normal exception. All higher-level languages have a function to shut down the process immediately, and that would be sys._exit() in python, but there is also sys.exit() that does kinda the same, but allows your finally blocks to run first, and is implemented as an exception.
What you want should be done by having a try - except block at the lowest level of your application. The behaviour should be in the handler code, not in the exception.

Most reliable way of exiting out of a function on a failed try

What is the best way to except out of ALL potential errors?
## Try to...
try:
## Print
print "hi"
## On failure to get data
except Exception:
## Exit out of current function
return
or
## Try to...
try:
## Print
print "hi"
## On failure to get data
except:
## Exit out of current function
return
or are there better ways?
Thanks in advance
- Hyflex
Generally, always catch specific errors you know will occur. Especially if you catch everything, (That is, except:) you will catch KeyboardInterrupt and make your program not be stoppable by Ctrl+C; SystemExit that is used to kill a thread, and so forth... While catching Exception is slightly better, it will still lose too much context; the exceptional condition that occurs might be other than you expected. Thus always catch IOError, ValueError, TypeError and so forth, by their names.
Update
There is 1 case where you want to use except Exception; at a top level of a program, or an action where you want to make sure that the whole program does not crash due to an uncaught Exception.
Never use a bare except:. If you do, you'll wind up catching things like SystemExit and KeyboardInterrupt, which are not intended to be caught in most code.
Ideally, you should try to be as specific as possible - for example, catching IOError for a failing print. If you can't predict exactly what exceptions you're concerned about, then at the very least you should use except Exception to avoid the aforementioned problem.

Why finally block is executing after calling sys.exit(0) in except block?

I'm new to Python. I just want to know why the finally block is executing after calling sys.exit(0) in the except block?
Code:
import sys
def divide_by_zero():
try:
10/0
print "It will never print"
except Exception:
sys.exit(0)
print "Printing after exit"
finally:
print "Finally will always print"
divide_by_zero()
Btw., I was just trying to do the same thing as in Java, where the finally block is not executed when System.exit(0) is in the catch block.
All sys.exit() does is raise an exception of type SystemExit.
From the documentation:
Exit from Python. This is implemented by raising the SystemExit
exception, so cleanup actions specified by finally clauses of try
statements are honored, and it is possible to intercept the exit
attempt at an outer level.
If you run the following, you'll see for yourself:
import sys
try:
sys.exit(0)
except SystemExit as ex:
print 'caught SystemExit:', ex
As an alternative, os._exit(n) with the status code will stop the process bypassing much of the cleanup, including finally blocks etc.
You should use os._exit(0).
About your example:
A finally clause is always executed before leaving the try statement,
whether an exception has occurred or not.
This is from Error and Exceptions part of Python docs. So - your finally block will always be executed in example you show unless you will use os._exit(0). But you should use it wisely...

Is there a way to prevent a SystemExit exception raised from sys.exit() from being caught?

The docs say that calling sys.exit() raises a SystemExit exception which can be caught in outer levels. I have a situation in which I want to definitively and unquestionably exit from inside a test case, however the unittest module catches SystemExit and prevents the exit. This is normally great, but the specific situation I am trying to handle is one where our test framework has detected that it is configured to point to a non-test database. In this case I want to exit and prevent any further tests from being run. Of course since unittest traps the SystemExit and continues happily on it's way, it is thwarting me.
The only option I have thought of so far is using ctypes or something similar to call exit(3) directly but this seems like a pretty fugly hack for something that should be really simple.
You can call os._exit() to directly exit, without throwing an exception:
import os
os._exit(1)
This bypasses all of the python shutdown logic, such as the atexit module, and will not run through the exception handling logic that you're trying to avoid in this situation. The argument is the exit code that will be returned by the process.
As Jerub said, os._exit(1) is your answer. But, considering it bypasses all cleanup procedures, including finally: blocks, closing files, etc, it should really be avoided at all costs. So may I present a safer(-ish) way of using it?
If your problem is SystemExit being caught at outer levels (i.e., unittest), then be the outer level yourself! Wrap your main code in a try/except block, catch SystemExit, and call os._exit() there, and only there! This way you may call sys.exit normally anywhere in the code, let it bubble out to the top level, gracefully closing all files and running all cleanups, and then calling os._exit.
You can even choose which exits are the "emergency" ones. The code below is an example of such approach:
import sys, os
EMERGENCY = 255 # can be any number actually
try:
# wrap your whole code here ...
# ... some code
if x: sys.exit()
# ... some more code
if y: sys.exit(EMERGENCY) # use only for emergency exits
... # yes, this is valid python!
# Might instead wrap all code in a function
# It's a common pattern to exit with main's return value, if any
sys.exit(main())
except SystemExit as e:
if e.code != EMERGENCY:
raise # normal exit, let unittest catch it at the outer level
else:
os._exit(EMERGENCY) # try to stop *that*!
As for e.code that some readers were unaware of, it is documented, as well as the attributes of all built-in exceptions.
You can also use quit, see example below:
while True:
print('Type exit to exit.')
response = input()
if response == 'exit':
quit(0)
print('You typed ' + response + '.')

Categories