pytest
pytest copied to clipboard
pytest.exit documentation states returncode=None defaults to 0, but it actually defaults to 2
Content:
I've found a discrepancy between the documentation and the actual behavior of the pytest.exit function regarding the returncode parameter.
Documentation:
def exit(
reason: str = "",
returncode: int | None = None,
) -> NoReturn:
"""Exit testing process.
...
:param returncode:
Return code to be used when exiting pytest. None means the same as ``0`` (no error), same as :func:`sys.exit`.
:raises pytest.exit.Exception:
The exception that is raised.
"""
...
raise Exit(reason, returncode)
Observed Behavior:
While the documentation states that returncode=None should be treated the same as 0 (indicating no error), the actual behavior is different. When pytest.exit() is called without specifying the returncode parameter or when returncode=None is passed, the process exits with a status code of 2, not 0.
Code Example (from the documentation snippet):
def pytest_runtestloop(session: Session) -> object | None:
pytest.exit() # If it were called with returncode=None or omitted, it would exit with 2.
Expected Behavior:
The behavior should match the documentation: returncode=None should result in an exit status code of 0.
Actual Behavior(in hooks):
returncode=None results in an exit status code of 2.
This inconsistency between the documented and actual behavior is confusing and can lead to incorrect assumptions in scripts or automation that rely on the exit status code from pytest.exit.
The code responsible for this behavior should be reviewed, and either the documentation should be updated to correctly state that None defaults to 2, or the implementation should be modified to align with the documented default of 0.
def pytest_sessionfinish(
session: Session,
exitstatus: int | ExitCode,
) -> None:
"""Called after whole test run finished, right before returning the exit status to the system.
:param session: The pytest session object.
:param exitstatus: The status which pytest will return to the system.
Use in conftest plugins
=======================
Any conftest file can implement this hook.
"""
exitstatus = ExitCode(exitstatus)
assert exitstatus is ExitCode.INTERRUPTED # pass
assert exitstatus is ExitCode.OK # fail
pytest version: 8.3.5 Python version: 3.11 Operating System: win
Your code example doesn't work reason is undefined. Here is a simpler example in a test file, which reproduces the same issue though:
import pytest
def test_x():
pytest.exit()
This seems to be because of:
https://github.com/pytest-dev/pytest/blob/89b84cb56295c46e1d8834b599e858bc65c15a5b/src/_pytest/main.py#L297-L300
Where the 2 you're seeing is ExitCode.INTERRUPTED.
Also see:
- #11695
- #11698
which might have been wrong all along, based on https://github.com/pytest-dev/pytest/issues/11695#issuecomment-1855644496 maybe.
@The-Compiler Thank you for the clear explanation! Setting the returncode manually temporarily fixed the issue. Much appreciated!