https://github.com/python/cpython/commit/4532b36db5b9a43f63bf295aaf51df426e4c488d
commit: 4532b36db5b9a43f63bf295aaf51df426e4c488d
branch: main
author: Serhiy Storchaka <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-09-23T13:09:32+03:00
summary:
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.
files:
A Misc/NEWS.d/next/Library/2026-09-17-14-00-00.gh-issue-157672.tksigs.rst
M Lib/test/test_tkinter/test_misc.py
M Modules/_tkinter.c
diff --git a/Lib/test/test_tkinter/test_misc.py
b/Lib/test/test_tkinter/test_misc.py
index c9d402e11a8826f..5c1eea786698595 100644
--- a/Lib/test/test_tkinter/test_misc.py
+++ b/Lib/test/test_tkinter/test_misc.py
@@ -3,6 +3,7 @@
import os
import gc
import platform
+import signal
import sys
import textwrap
import time
@@ -13,6 +14,7 @@
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
diff --git
a/Misc/NEWS.d/next/Library/2026-09-17-14-00-00.gh-issue-157672.tksigs.rst
b/Misc/NEWS.d/next/Library/2026-09-17-14-00-00.gh-issue-157672.tksigs.rst
new file mode 100644
index 000000000000000..a751a2f9dc406b1
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-09-17-14-00-00.gh-issue-157672.tksigs.rst
@@ -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.
diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c
index f5fb1841f0d5940..746c39e6d3f4a20 100644
--- a/Modules/_tkinter.c
+++ b/Modules/_tkinter.c
@@ -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
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]