fix: stop searches gracefully on Windows console Ctrl-C - #1386
Merged
MilesCranmer merged 3 commits intoSep 27, 2026
Merged
Conversation
Co-authored-by: Miles Cranmer <miles.cranmer@gmail.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
A Ctrl-C arriving while the original SIGINT handler is installed raises KeyboardInterrupt, which could skip registering or removing the console handler and leave Windows holding a freed callback. The test now sends its interrupt once the fit has armed the search, instead of after a fixed delay. Co-authored-by: Miles Cranmer <miles.cranmer@gmail.com>
Co-authored-by: Miles Cranmer <miles.cranmer@gmail.com>
MilesCranmer
approved these changes
Sep 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pressing Ctrl-C in a Windows terminal during
model.fitkills the Python process. #1329 made interrupts stop the search gracefully from Jupyter on Windows, but a console Ctrl-C never reaches Python.Julia registers a console control handler at startup (
SetConsoleCtrlHandler(sigint_handler, 1)insrc/signals-win.c). Windows calls console handlers last-registered first, so Julia's runs before CPython's, returns TRUE, and exits the process with code 130. Python's SIGINT handler, and with it the stop byte thatExternalStoppolls for, never fires.For the duration of the search, PySR now registers its own console handler. Because it is registered last, it runs first. It passes
CTRL_C_EVENTto Python through_thread.interrupt_main(), the same route Jupyter's interrupt already takes, and it leaves other console events to the existing handlers. This does for Windows what thesigactionsave and restore already does for POSIX, sointerrupt.pyhas one if/else covering both platforms.TestSubprocessInterruptnow runs on Windows. The child process interrupts itself. On POSIX it sendsos.kill(os.getpid(), SIGINT). On Windows, where it is launched withCREATE_NEW_CONSOLE, it callsGenerateConsoleCtrlEvent(CTRL_C_EVENT, 0). The child runs a warm-up fit first so the interrupt lands on a running search, and it now requires non-empty partial results.Verification,
python -m pysr test interrupt:AssertionError: 130 != 0 : child failedRan 11 tests,OK (skipped=5); the subprocess test ran and passed, and the five skips are the POSIX-onlysigactionunit testsRan 11 tests,OK, no skipsRan 11 tests,OK