2

For example, I've something using the "with" statement, and I do something inside the "with" that can throw an exception, and I want to catch the exception so that I can use sys.exit(0) / sys.exit(1) so the pass / fail result can be picked up by the calling script/shell.

with open("test.txt", "r") as f:
    try:
        do_something_with(f)
    except Exception as e:
        sys.exit(1)
    else:
        sys.exit(0)

In my case, it's not a file I'm opening but a connection to a server, and I just want to know if the context manager's __exit__ will get called properly, or if sys.exit() somehow bypasses it?

  • No, only `sys._exit` falls through `finally` and context managers. – STerliakov Aug 31 '23 at 21:48
  • 1
    Does this answer your question? [Does 'finally' always execute in Python?](https://stackoverflow.com/questions/49262379/does-finally-always-execute-in-python) – STerliakov Aug 31 '23 at 21:48
  • 1
    (the linked duplicate should be considered together with https://stackoverflow.com/questions/26096435/is-python-with-statement-exactly-equivalent-to-a-try-except-finally-bloc) – STerliakov Aug 31 '23 at 21:49

1 Answers1

4

Yes, the context manager's __exit__ will still be called.

You can test this yourself by creating your own dummy context manager:

import contextlib
import sys


@contextlib.contextmanager
def my_context_manager():
    try:
        print("enter")
        yield
    finally:
        print("exit")


with my_context_manager():
    print("inside")
    sys.exit(1)

Running this script outputs

enter
inside
exit

This should make sense, since sys.exit works by raising SystemExit, which is just a slightly special exception that does not inherit from Exception. Stack unwinding happens the same as with any other exception. You can even catch it if you like:

try:
    sys.exit(1)
except SystemExit:
    print("caught exit")

print("I survived sys.exit()!")

outputs

caught exit
I survived sys.exit()!
Brian61354270
  • 8,690
  • 4
  • 21
  • 43
  • 1
    "Try it yourself" is a great *additional* proof. The fact that something works in some repro case does not mean it's always true (consider UB in c++ or race conditions with `threading` in python as examples). This answer would benefit from explaining why such behaviour is guaranteed by language specification. – STerliakov Aug 31 '23 at 21:52
  • Thanks. This answer is simple and clear. The other suggestions got deeper into other conditions that may / may not cause the `finally` statement to get called, e.g. os.exit() is definitely going to bypass it. I think the understanding that sys.exit() simply raises the SystemExit exception is quite key too. With that understanding, it is obvious that calling sys.exit() inside `with` will be handled properly as expected. – Steven Dickinson Sep 01 '23 at 07:00