https://github.com/python/cpython/commit/5f508b96a7395cad0563e3a19533c4bbf151017b
commit: 5f508b96a7395cad0563e3a19533c4bbf151017b
branch: 3.14
author: Serhiy Storchaka <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-09-23T10:52:39Z
summary:
[3.14] gh-157672: Keep Python's signal handlers when Tk is initialized on macOS
(GH-157673) (GH-157988)
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.
(cherry picked from commit 4532b36db5b9a43f63bf295aaf51df426e4c488d)
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 cc44449027f173d..8bd93ff77d6cc44 100644
--- a/Lib/test/test_tkinter/test_misc.py
+++ b/Lib/test/test_tkinter/test_misc.py
@@ -1,5 +1,6 @@
import functools
import platform
+import signal
import sys
import textwrap
import unittest
@@ -9,6 +10,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,
@@ -1913,5 +1915,17 @@ 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)
+
+
if __name__ == "__main__":
unittest.main()
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 22126b67d8f4a0b..9b13c7ace7f4f29 100644
--- a/Modules/_tkinter.c
+++ b/Modules/_tkinter.c
@@ -34,6 +34,8 @@ Copyright (C) 1994 Steen Lumholt.
#include "pycore_sysmodule.h" // _PySys_GetOptionalAttrString()
#include "pycore_unicodeobject.h" // _PyUnicode_AsUTF8String
+#include <signal.h> // SIGINT
+
#ifdef MS_WINDOWS
# include <windows.h>
#endif
@@ -251,7 +253,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]