[Python] pytest catching SystemExit, but exc_info.value.code is not the actual integer exit...

Discussão em 'Python' iniciado por Stack, Junho 3, 2025.

  1. Stack

    Stack Membro Participativo

    When using pytest and verifying that sys.exit was called, the ExecutionInfo object attribute "value.code" does not reliably contain the genuine integer exit code.
    The "value.code" contains something subtly different: the value that was passed to sys.exit (or None, if no arg).

    Am I overlooking something?
    There's no access to the genuine integer exit code, right?
    (And that's not so surprising because the final integer exit code might yet be changed on the way out to 120 if there's a problem during cleanup.)

    • if sys.exit(0) was called, then exc_info.value.code gets 0
    • if sys.exit() was called, then exc_info.value.code gets None, but the exit code is 0
    • if sys.exit(1) was called, then exc_info.value.code gets 1
    • if sys.exit('Trouble') was called, then exc_info.value.code gets 'Trouble', but the exit code is 1

    It seems like exc_info.value.code is an integer exit code ONLY when sys.exit is passed an integer exit code. Not when the exit code is implicitly 0 due to no args, or implicitly 1 due to a string arg.

    Is there a different attribute of exc_info that I'd reliably find the exit code?

    It feels like the exit code is not actually available on the SystemExit exception object or at least the ExceptionInfo object that pytest gives me, the exit code is determined later when something HANDLES the SystemExit exception while exiting.

    (this in Python 3.10.11, pytest 8.3.5)
    Thx!
    John R.

    Also, I did read these...


    These 4 tests pass because I commented out the assertion I initially expected to pass, and put in the assertion that does pass.

    import re
    import sys


    def test_sysexit_0():
    with pytest.raises(SystemExit) as exc_info:
    sys.exit(0) # exit code should be 0

    assert exc_info.value.code == 0


    def test_sysexit_2():
    with pytest.raises(SystemExit) as exc_info:
    sys.exit(2) # exit code should be 2

    assert exc_info.value.code == 2


    def test_sysexit_noargs():
    with pytest.raises(SystemExit) as exc_info:
    sys.exit() # exit code should be 0

    # This assertion fails, because code is None
    # assert exc_info.value.code == 0
    assert exc_info.value.code is None


    def test_sysexit_msg():
    with pytest.raises(SystemExit,
    match='cmd: bad usage') as exc_info:
    sys.exit('cmd: bad usage unrecognized option') # exit code should be 1

    # This assertion fails, because code is the string
    # assert exc_info.value.code == 1
    assert re.match('cmd: bad usage', exc_info.value.code)

    Continue reading...

Compartilhe esta Página