Skip to content

gh-152132: Handle sys.exit() in Py_RunMain command and file paths#152191

Open
tangyuan0821 wants to merge 6 commits into
python:mainfrom
tangyuan0821:152132
Open

gh-152132: Handle sys.exit() in Py_RunMain command and file paths#152191
tangyuan0821 wants to merge 6 commits into
python:mainfrom
tangyuan0821:152132

Conversation

@tangyuan0821

@tangyuan0821 tangyuan0821 commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Switch to low-level APIs so SystemExit goes through pymain_exit_err_print() instead of exit().

Two issues introduced by the Py_RunMain SystemExit fix:

1. pymain_run_command lost traceback source lines for -c commands
   because PyRun_StringFlags does not register source in linecache.
   Add _PyRun_SimpleStringFlagsEx, which returns PyObject* without
   calling PyErr_Print(), and use it in pymain_run_command with the
   "<string>" name so source linecache registration is preserved.

2. _PyRun_SimpleFileObjectEx could lose exceptions during cleanup
   when PyDict_PopString fails (e.g. under low-memory conditions).
   Save and restore the original exception around cleanup code when
   the main code failed; use PyErr_Print() for cleanup errors when
   the main code succeeded to match legacy behavior.

@ZeroIntensity ZeroIntensity left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a test case.

Comment thread Modules/main.c Outdated
Comment thread Python/pythonrun.c Outdated
Comment thread Python/pythonrun.c Outdated
- Rename _PyRun_SimpleFileObjectEx → _PyRun_SimpleFileObjectNoPrint to
  avoid the deprecated 'Ex' suffix. Make _PyRun_SimpleFileObject a thin
  wrapper around it to avoid code duplication.
- Rename _PyRun_SimpleStringFlagsEx → _PyRun_SimpleStringFlagsNoPrint
  and make _PyRun_SimpleStringFlagsWithName a thin wrapper similarly.
- Rename single-letter variable 'v' and 'res' to 'result' throughout.
- Add test cases for sys.exit() handling via -c, file, -m and message.
@tangyuan0821

Copy link
Copy Markdown
Contributor Author

Please add a test case.

Added 5 test cases in Lib/test/test_runpy.py covering sys.exit() via -c, file, -m, default exit code, and exit with message.

Comment thread Lib/test/test_runpy.py
Comment thread Modules/main.c
Add test_run_main_system_exit_module and test_run_main_system_exit_command_message
to _testembed.c and test_embed.py, covering the remaining sys.exit() paths
mentioned in the review feedback (-m module and string message variants).
@vstinner

vstinner commented Jul 7, 2026

Copy link
Copy Markdown
Member

Hi. Thanks for your interesting fix!

I wrote a different approach in PR gh-153294: instead of returning a PyObject*, I added E_EXITCODE return value and int *exitcode parameter to PyRun functions. Your approach requires moving error handling (basically calling PyErr_Print()) to the caller.

@vstinner

vstinner commented Jul 8, 2026

Copy link
Copy Markdown
Member

The legacy REPL of pymain_run_stdin() doesn't handle SystemExit properly:

    PyCompilerFlags cf = _PyCompilerFlags_INIT;
    run = PyRun_AnyFileExFlags(stdin, "<stdin>", 0, &cf);
    return (run != 0);

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants