Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 766
John Avatar asked Oct 06 '08 05:10

John


People also ask

How do you handle a sys exit exception?

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.

Which of the following exceptions is raised while using sys exit ()?

In Python, SystemExit is an exception that is raised by the sys. exit() method. In general, all exceptions must be derived from BaseException which are instances of a class.

What is the purpose of the sys exit () function?

exit() function allows the developer to exit from Python. The exit function takes an optional argument, typically an integer, that gives an exit status. Zero is considered a “successful termination”.

What is raise SystemExit?

raise SystemExit()The top level interpreter catches this special exception class and triggers its exit routine. This includes such steps as running all atexit functions, deleting all objects, and finally calling the OS exit function.


2 Answers

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.

like image 50
Jerub Avatar answered Oct 07 '22 01:10

Jerub


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.

like image 36
MestreLion Avatar answered Oct 07 '22 00:10

MestreLion