gh-157672: Keep Python's signal handlers when Tk is initialized on macOS (GH-157673)

Tk on macOS replaces the SIGINT, SIGHUP and SIGTERM handlers with its
own, which exits the process, so Ctrl-C terminated a tkinter program
instead of raising KeyboardInterrupt.  Save the handlers installed by
Python before Tk_Init() and restore them after it.

This affects Tk 8.6.11 to 8.6.18 and 9.0 to 9.0.4.  Tk itself is fixed
in 8.6.19 and 9.0.5.
This commit is contained in:
Serhiy Storchaka authored and GitHub committed 2026-09-23 13:09:32 +03:00
1 parent 55ecc0a409
commit 4532b36db5
3 files changed
+39 -1

No files matched your search

+14
View File
@@ -3,6 +3,7 @@ import functools
import os
import gc
import platform
import signal
import sys
import textwrap
import time
@@ -13,6 +14,7 @@ from tkinter import TclError, ttk
import enum
from test import support
from test.support import os_helper
from test.support.isolation import runInSubprocess
from test.support.script_helper import assert_python_ok
from test.test_tkinter.support import setUpModule # noqa: F401
from test.test_tkinter.support import (AbstractTkTest, AbstractDefaultRootTest,
@@ -2149,6 +2151,18 @@ def _info_commands(widget, pattern=None):
return widget.tk.splitlist(widget.tk.call('info', 'commands', pattern))
class SignalTest(unittest.TestCase):
@runInSubprocess()
def test_sigint_handler(self):
# gh-157672: Tk on macOS replaced the SIGINT handler with its own,
# which exits the process.
root = tkinter.Tk()
self.addCleanup(root.destroy)
with self.assertRaises(KeyboardInterrupt):
signal.raise_signal(signal.SIGINT)
class TclObjTypeTest(AbstractTkTest, unittest.TestCase):
# See FromObj() in Modules/_tkinter.c: Tcl object types are converted to
# appropriate Python types. These conversions only happen in the object
@@ -0,0 +1,4 @@
Fix :mod:`tkinter` on macOS: creating a :class:`~tkinter.Tk` instance no
longer replaces the Python handlers of SIGINT, SIGHUP and SIGTERM with Tk's
handler which exits the process, so Ctrl-C raises :exc:`KeyboardInterrupt`
again.
+21 -1
View File
@@ -33,6 +33,8 @@ Copyright (C) 1994 Steen Lumholt.
#include "pycore_long.h" // _PyLong_IsNegative()
#include "pycore_unicodeobject.h" // _PyUnicode_AsUTF8String
#include <signal.h> // SIGINT
#ifdef MS_WINDOWS
# include <windows.h>
#endif
@@ -227,7 +229,25 @@ Tkinter_TkInit(Tcl_Interp *interp)
does not search. Mount the DLL using Zipfs if possible. */
mount_tk_dll_zip();
#endif
return Tk_Init(interp);
#ifdef __APPLE__
/* Tk on macOS replaces the handlers of these signals with its own,
which exits the process. Keep the handlers installed by Python
(gh-157672). */
static const int signals[] = {SIGINT, SIGHUP, SIGTERM};
PyOS_sighandler_t handlers[Py_ARRAY_LENGTH(signals)];
for (size_t i = 0; i < Py_ARRAY_LENGTH(signals); i++) {
handlers[i] = PyOS_getsig(signals[i]);
}
#endif
int result = Tk_Init(interp);
#ifdef __APPLE__
for (size_t i = 0; i < Py_ARRAY_LENGTH(signals); i++) {
if (handlers[i] != SIG_DFL) {
PyOS_setsig(signals[i], handlers[i]);
}
}
#endif
return result;
}
/* The threading situation is complicated. Tcl is not thread-safe, except