mirror of
https://github.com/python/cpython.git
synced 2026-10-28 10:25:05 +08:00
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:
1 parent
55ecc0a409
commit
4532b36db5
3 files changed
+39
-1
No files matched your search
@@ -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
@@ -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
|
||||
|
||||
Reference in new issue
Block a user