Skip to content

fix: preserve sys.exit() exit codes in non-interactive mode#15158

Open
Sarah-2003 wants to merge 1 commit intoipython:mainfrom
Sarah-2003:fix-exit-code-preservation
Open

fix: preserve sys.exit() exit codes in non-interactive mode#15158
Sarah-2003 wants to merge 1 commit intoipython:mainfrom
Sarah-2003:fix-exit-code-preservation

Conversation

@Sarah-2003
Copy link

Summary

Fixes #15132.

When running ipython -c "import sys;sys.exit(2)", IPython returned exit code 1 instead of 2. Regular Python correctly returns 2.

Root cause: TerminalIPythonApp.start() in ipapp.py hardcoded sys.exit(1) for all failed executions, regardless of the actual exit code passed to sys.exit().

Changes

  • IPython/terminal/ipapp.py -- Extract the original exit code from last_execution_result.error_in_exec when the error is a SystemExit. Falls back to exit code 1 for non-SystemExit failures.
  • IPython/core/shellapp.py -- Add a separate except SystemExit clause in the file execution path of _run_cmd_line_code() to preserve exit codes when running script files.
  • tests/test_shellapp.py -- Add 8 tests covering exit code preservation for -c execution and script file execution (codes 0, 1, 2, 42, no-arg, normal execution).

How it works

When sys.exit(N) is called inside user code, InteractiveShell.run_code() catches the SystemExit and stores it in result.error_in_exec. The fix reads error_in_exec.code to extract the original exit code instead of discarding it.

Edge cases handled:

  • sys.exit(0) and sys.exit() -- exit code 0
  • sys.exit(N) for any integer N -- preserves N
  • sys.exit("message") -- exit code 1 (matches Python behavior)
  • Non-SystemExit failures -- exit code 1 (unchanged)

Test plan

  • ipython -c "import sys; sys.exit(2)" returns code 2 (was 1)
  • ipython -c "import sys; sys.exit(42)" returns code 42 (was 1)
  • ipython -c "import sys; sys.exit(0)" returns code 0
  • ipython -c "print('hello')" returns code 0 (unchanged)
  • Script file with sys.exit(2) returns code 2
  • All 3 modified files pass syntax check

When running `ipython -c "import sys;sys.exit(2)"`, IPython incorrectly
returned exit code 1 instead of 2. The exit code was hardcoded to 1 in
the start() method of TerminalIPythonApp regardless of the actual code
passed to sys.exit().

Extract the original exit code from the stored SystemExit exception in
last_execution_result.error_in_exec. Also handle SystemExit separately
in the file execution path in _run_cmd_line_code().

Fixes ipython#15132
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ipython turns all non-zero exit codes to 1 when script ran with "ipython -c script.py" uses sys.exit()

1 participant