summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Foord <michael@voidspace.org.uk>2013-01-29 23:07:57 (GMT)
committerMichael Foord <michael@voidspace.org.uk>2013-01-29 23:07:57 (GMT)
commit6debd769393c9c5cdd4feb2a0c74bda173a13b1e (patch)
treefe028d9d93b7da53295cb24357abfe192060baff
parent45c4375ea7da4a78e9d5dc7b79f98b7882cc7640 (diff)
downloadcpython-6debd769393c9c5cdd4feb2a0c74bda173a13b1e.zip
cpython-6debd769393c9c5cdd4feb2a0c74bda173a13b1e.tar.gz
cpython-6debd769393c9c5cdd4feb2a0c74bda173a13b1e.tar.bz2
Closes issue 15505. unittest.installHandler and non-callable signal handlers.
-rw-r--r--Lib/unittest/signals.py16
-rw-r--r--Lib/unittest/test/test_break.py32
-rw-r--r--Misc/NEWS3
3 files changed, 50 insertions, 1 deletions
diff --git a/Lib/unittest/signals.py b/Lib/unittest/signals.py
index fc31043..e6a5fc5 100644
--- a/Lib/unittest/signals.py
+++ b/Lib/unittest/signals.py
@@ -9,6 +9,20 @@ __unittest = True
class _InterruptHandler(object):
def __init__(self, default_handler):
self.called = False
+ self.original_handler = default_handler
+ if isinstance(default_handler, int):
+ if default_handler == signal.SIG_DFL:
+ # Pretend it's signal.default_int_handler instead.
+ default_handler = signal.default_int_handler
+ elif default_handler == signal.SIG_IGN:
+ # Not quite the same thing as SIG_IGN, but the closest we
+ # can make it: do nothing.
+ def default_handler(unused_signum, unused_frame):
+ pass
+ else:
+ raise TypeError("expected SIGINT signal handler to be "
+ "signal.SIG_IGN, signal.SIG_DFL, or a "
+ "callable object")
self.default_handler = default_handler
def __call__(self, signum, frame):
@@ -54,4 +68,4 @@ def removeHandler(method=None):
global _interrupt_handler
if _interrupt_handler is not None:
- signal.signal(signal.SIGINT, _interrupt_handler.default_handler)
+ signal.signal(signal.SIGINT, _interrupt_handler.original_handler)
diff --git a/Lib/unittest/test/test_break.py b/Lib/unittest/test/test_break.py
index 77ce201..75532f4 100644
--- a/Lib/unittest/test/test_break.py
+++ b/Lib/unittest/test/test_break.py
@@ -13,9 +13,12 @@ import unittest
@unittest.skipIf(sys.platform == 'freebsd6', "Test kills regrtest on freebsd6 "
"if threads have been used")
class TestBreak(unittest.TestCase):
+ int_handler = None
def setUp(self):
self._default_handler = signal.getsignal(signal.SIGINT)
+ if self.int_handler is not None:
+ signal.signal(signal.SIGINT, self.int_handler)
def tearDown(self):
signal.signal(signal.SIGINT, self._default_handler)
@@ -72,6 +75,10 @@ class TestBreak(unittest.TestCase):
def testSecondInterrupt(self):
+ # Can't use skipIf decorator because the signal handler may have
+ # been changed after defining this method.
+ if signal.getsignal(signal.SIGINT) == signal.SIG_IGN:
+ self.skipTest("test requires SIGINT to not be ignored")
result = unittest.TestResult()
unittest.installHandler()
unittest.registerResult(result)
@@ -121,6 +128,10 @@ class TestBreak(unittest.TestCase):
def testHandlerReplacedButCalled(self):
+ # Can't use skipIf decorator because the signal handler may have
+ # been changed after defining this method.
+ if signal.getsignal(signal.SIGINT) == signal.SIG_IGN:
+ self.skipTest("test requires SIGINT to not be ignored")
# If our handler has been replaced (is no longer installed) but is
# called by the *new* handler, then it isn't safe to delay the
# SIGINT and we should immediately delegate to the default handler
@@ -250,3 +261,24 @@ class TestBreak(unittest.TestCase):
test()
self.assertNotEqual(signal.getsignal(signal.SIGINT), default_handler)
+
+@unittest.skipUnless(hasattr(os, 'kill'), "Test requires os.kill")
+@unittest.skipIf(sys.platform =="win32", "Test cannot run on Windows")
+@unittest.skipIf(sys.platform == 'freebsd6', "Test kills regrtest on freebsd6 "
+ "if threads have been used")
+class TestBreakDefaultIntHandler(TestBreak):
+ int_handler = signal.default_int_handler
+
+@unittest.skipUnless(hasattr(os, 'kill'), "Test requires os.kill")
+@unittest.skipIf(sys.platform =="win32", "Test cannot run on Windows")
+@unittest.skipIf(sys.platform == 'freebsd6', "Test kills regrtest on freebsd6 "
+ "if threads have been used")
+class TestBreakSignalIgnored(TestBreak):
+ int_handler = signal.SIG_IGN
+
+@unittest.skipUnless(hasattr(os, 'kill'), "Test requires os.kill")
+@unittest.skipIf(sys.platform =="win32", "Test cannot run on Windows")
+@unittest.skipIf(sys.platform == 'freebsd6', "Test kills regrtest on freebsd6 "
+ "if threads have been used")
+class TestBreakSignalDefault(TestBreak):
+ int_handler = signal.SIG_DFL
diff --git a/Misc/NEWS b/Misc/NEWS
index 7ebe3f8..e9cd8c7 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -216,6 +216,9 @@ Core and Builtins
Library
-------
+- Issue #15505: `unittest.installHandler` no longer assumes SIGINT handler is
+ set to a callable object.
+
- Issue #12004: Fix an internal error in PyZipFile when writing an invalid
Python file. Patch by Ben Morgan.