You're looking for calls to sys.exit(...) (exit(...) calls sys.exit(...)) in the script. The argument to that method is returned to the environment as the exit code.
It's fairly likely that the script is never calling the exit(...) method, and that 0 is the default exit code.
Helloings,
on a basic computer course I ran into a problem where I can't use any built-in exit functions or libraries, but I have to somehow terminate the program mid-function. Simply breaking out of that function won't likely help as it would just move onto the next function with invalid values, crashing the whole thing. Any tips?
You're looking for calls to sys.exit(...) (exit(...) calls sys.exit(...)) in the script. The argument to that method is returned to the environment as the exit code.
It's fairly likely that the script is never calling the exit(...) method, and that 0 is the default exit code.
From the documentation for sys.exit:
The optional argument arg can be an integer giving the exit status (defaulting to zero), or another type of object. If it is an integer, zero is considered “successful termination” and any nonzero value is considered “abnormal termination” by shells and the like. Most systems require it to be in the range 0-127, and produce undefined results otherwise. Some systems have a convention for assigning specific meanings to specific exit codes, but these are generally underdeveloped; Unix programs generally use 2 for command line syntax errors and 1 for all other kind of errors.
One example where exit codes are used are in shell scripts. In Bash you can check the special variable $? for the last exit status:
me@mini:~$ python -c ""; echo $?
0
me@mini:~$ python -c "import sys; sys.exit(0)"; echo $?
0
me@mini:~$ python -c "import sys; sys.exit(43)"; echo $?
43
Personally I try to use the exit codes I find in /usr/include/asm-generic/errno.h (on a Linux system), but I don't know if this is the right thing to do.
bash - How to return status code in Python without actually exiting the process? - Stack Overflow
Setting exit code in Python when an exception is raised - Stack Overflow
is raise SystemExit(exit_code) the right way to return a non-zero exit status?
What is Python's default exit code? - Stack Overflow
Videos
Take a look at the traceback module. You could do the following:
import sys, traceback
try:
raise Exception()
except:
traceback.print_exc()
sys.exit(3)
This will write traceback to standard error and exit with code 3.
You can use sys.excepthook to handle uncaught exceptions:
import sys
import traceback
from types import TracebackType
def handle_exception(
type_: type[BaseException], value: BaseException, tb: TracebackType | None
) -> None:
traceback.print_tb(tb)
sys.exit(3)
sys.excepthook = handle_exception
raise Exception
Output:
$ python test.py
File "/tmp/scratch/scratch005/test.py", line 15, in <module>
raise Exception
$ echo $?
3
This answer also shows how to specially handle specific types of exceptions while falling back to the default behavior for all other types. For example, you could treat ExceptionWhichCausesExitCode3 specially, while exiting in a normal way for other exceptions
sys.exit documents a default exit status of 0, and os._exit's docs specify a UNIX-like OS constant for "normal" exit status, os.EX_OK, but there is no documented guarantee I can find for the exit status in general.
Aside from that, the best I can give you is that in CPython, the python executable (including python.exe/pythonw.exe on Windows) is implemented in python.c by calling Py_Main and returning whatever it returns; per the documented guarantees on Py_Main, the exit status is:
0if the interpreter exits normally (i.e., without an exception),1if the interpreter exits due to an exception, or2if the parameter list does not represent a valid Python command line.Note that if an otherwise unhandled
SystemExitis raised, this function will not return1, but exit the process, as long asPy_InspectFlagis not set.
so this implies that simply running off the end of the __main__ module without an active exception should always return 0 for CPython, though alternate interpreters are not technically required to do the same.
This tracks with the implied exit status rules expected of most applications; while nothing explicitly says Python has to follow those rules, it would be extremely unusual for a tool that grew up in the command line UNIX-like world to violate those conventions.
If you look at the cpython source code:
main()inPrograms/python.creturns the return value ofPy_Main()Py_Main()inModules/main.creturns the return value ofrun_file()run_file(), also inModules/main.creturns0unlessPyRun_AnyFileExFlags()returns non-zeroPyRun_AnyFileExFlags()inPython/pythonrun.cwillexit()in the event of aSystemExitexception and so will not return if the script sets an exit code. It will only return non-zero if there is an internal error.
So the return value of run_file() is what makes the default exit code of a script 0.
As JBernardo pointed out, sys.exit() raises an exception. This exception is SystemExit. When it is not handled by the user code, the interpreter exits cleanly (a debugger debugging the program can catch it and keep control of the program, thanks to this mechanism, for instance)—as opposed to os._exit(), which is an unconditional abortion of the program.
This exception is not caught by except Exception:, because SystemExit does not inherit from Exception. However, it is caught by a naked except: clause.
So, if your program sees an exception, you may want to catch fewer exceptions by using except Exception: instead of except:. That said, catching all exceptions is discouraged, because this might hide real problems, so avoid it if you can, by making the except clause (if any) more specific.
My understanding of why this SystemExit exception mechanism is useful is that the user code goes through any finally clause after a sys.exit() found in an except clause: files can be closed cleanly, etc.; then the interpreter catches any SystemExit that was not caught by the user and exits for good (a debugger would instead catch it so as to keep the interpreter running and obtain information about the program that exited).
You can do what you're looking for by doing this:
import os
os._exit(1)