summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorGiampaolo Rodola' <g.rodola@gmail.com>2014-04-04 13:34:17 (GMT)
committerGiampaolo Rodola' <g.rodola@gmail.com>2014-04-04 13:34:17 (GMT)
commite09fb7198ae2e4f737db7369006ad19e51699fbf (patch)
tree52a94575cd518a23b79430a0d89c66cbc839a2d5 /Lib
parentbcc174615ca2bd5fe60442407ca1411759d823cf (diff)
downloadcpython-e09fb7198ae2e4f737db7369006ad19e51699fbf.zip
cpython-e09fb7198ae2e4f737db7369006ad19e51699fbf.tar.gz
cpython-e09fb7198ae2e4f737db7369006ad19e51699fbf.tar.bz2
fix #21076: turn signal module constants into enums
Diffstat (limited to 'Lib')
-rw-r--r--Lib/signal.py84
-rw-r--r--Lib/test/test_doctest.py2
-rw-r--r--Lib/test/test_signal.py39
3 files changed, 120 insertions, 5 deletions
diff --git a/Lib/signal.py b/Lib/signal.py
new file mode 100644
index 0000000..90e5313
--- /dev/null
+++ b/Lib/signal.py
@@ -0,0 +1,84 @@
+import _signal
+from _signal import *
+from functools import wraps as _wraps
+from enum import IntEnum as _IntEnum
+
+_globals = globals()
+
+Signals = _IntEnum(
+ 'Signals',
+ {name: value for name, value in _globals.items()
+ if name.isupper()
+ and (name.startswith('SIG') and not name.startswith('SIG_'))
+ or name.startswith('CTRL_')})
+
+class Handlers(_IntEnum):
+ SIG_DFL = _signal.SIG_DFL
+ SIG_IGN = _signal.SIG_IGN
+
+_globals.update(Signals.__members__)
+_globals.update(Handlers.__members__)
+
+if 'pthread_sigmask' in _globals:
+ class Sigmasks(_IntEnum):
+ SIG_BLOCK = _signal.SIG_BLOCK
+ SIG_UNBLOCK = _signal.SIG_UNBLOCK
+ SIG_SETMASK = _signal.SIG_SETMASK
+
+ _globals.update(Sigmasks.__members__)
+
+
+def _int_to_enum(value, enum_klass):
+ """Convert a numeric value to an IntEnum member.
+ If it's not a known member, return the numeric value itself.
+ """
+ try:
+ return enum_klass(value)
+ except ValueError:
+ return value
+
+
+def _enum_to_int(value):
+ """Convert an IntEnum member to a numeric value.
+ If it's not a IntEnum member return the value itself.
+ """
+ try:
+ return int(value)
+ except (ValueError, TypeError):
+ return value
+
+
+@_wraps(_signal.signal)
+def signal(signalnum, handler):
+ handler = _signal.signal(_enum_to_int(signalnum), _enum_to_int(handler))
+ return _int_to_enum(handler, Handlers)
+
+
+@_wraps(_signal.getsignal)
+def getsignal(signalnum):
+ handler = _signal.getsignal(signalnum)
+ return _int_to_enum(handler, Handlers)
+
+
+if 'pthread_sigmask' in _globals:
+ @_wraps(_signal.pthread_sigmask)
+ def pthread_sigmask(how, mask):
+ sigs_set = _signal.pthread_sigmask(how, mask)
+ return set(_int_to_enum(x, Signals) for x in sigs_set)
+ pthread_sigmask.__doc__ = _signal.pthread_sigmask.__doc__
+
+
+@_wraps(_signal.sigpending)
+def sigpending():
+ sigs = _signal.sigpending()
+ return set(_int_to_enum(x, Signals) for x in sigs)
+
+
+if 'sigwait' in _globals:
+ @_wraps(_signal.sigwait)
+ def sigwait(sigset):
+ retsig = _signal.sigwait(sigset)
+ return _int_to_enum(retsig, Signals)
+ sigwait.__doc__ = _signal.sigwait
+
+del _globals, _wraps
diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py
index 56193e8..a1029ed 100644
--- a/Lib/test/test_doctest.py
+++ b/Lib/test/test_doctest.py
@@ -2897,7 +2897,7 @@ Invalid doctest option:
def test_main():
# Check the doctest cases in doctest itself:
- support.run_doctest(doctest, verbosity=True)
+ ret = support.run_doctest(doctest, verbosity=True)
# Check the doctest cases defined here:
from test import test_doctest
support.run_doctest(test_doctest, verbosity=True)
diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py
index a6f2c64..31e6d37 100644
--- a/Lib/test/test_signal.py
+++ b/Lib/test/test_signal.py
@@ -1,6 +1,7 @@
import unittest
from test import support
from contextlib import closing
+import enum
import gc
import pickle
import select
@@ -39,6 +40,22 @@ def ignoring_eintr(__func, *args, **kwargs):
return None
+class GenericTests(unittest.TestCase):
+
+ def test_enums(self):
+ for name in dir(signal):
+ sig = getattr(signal, name)
+ if name in {'SIG_DFL', 'SIG_IGN'}:
+ self.assertIsInstance(sig, signal.Handlers)
+ elif name in {'SIG_BLOCK', 'SIG_UNBLOCK', 'SIG_SETMASK'}:
+ self.assertIsInstance(sig, signal.Sigmasks)
+ elif name.startswith('SIG') and not name.startswith('SIG_'):
+ self.assertIsInstance(sig, signal.Signals)
+ elif name.startswith('CTRL_'):
+ self.assertIsInstance(sig, signal.Signals)
+ self.assertEqual(sys.platform, "win32")
+
+
@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
class InterProcessSignalTests(unittest.TestCase):
MAX_DURATION = 20 # Entire test should last at most 20 sec.
@@ -195,6 +212,7 @@ class PosixTests(unittest.TestCase):
def test_getsignal(self):
hup = signal.signal(signal.SIGHUP, self.trivial_signal_handler)
+ self.assertIsInstance(hup, signal.Handlers)
self.assertEqual(signal.getsignal(signal.SIGHUP),
self.trivial_signal_handler)
signal.signal(signal.SIGHUP, hup)
@@ -271,7 +289,7 @@ class WakeupSignalTests(unittest.TestCase):
os.close(read)
os.close(write)
- """.format(signals, ordered, test_body)
+ """.format(tuple(map(int, signals)), ordered, test_body)
assert_python_ok('-c', code)
@@ -604,6 +622,8 @@ class PendingSignalsTests(unittest.TestCase):
signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
os.kill(os.getpid(), signum)
pending = signal.sigpending()
+ for sig in pending:
+ assert isinstance(sig, signal.Signals), repr(pending)
if pending != {signum}:
raise Exception('%s != {%s}' % (pending, signum))
try:
@@ -660,6 +680,7 @@ class PendingSignalsTests(unittest.TestCase):
code = '''if 1:
import signal
import sys
+ from signal import Signals
def handler(signum, frame):
1/0
@@ -702,6 +723,7 @@ class PendingSignalsTests(unittest.TestCase):
def test(signum):
signal.alarm(1)
received = signal.sigwait([signum])
+ assert isinstance(received, signal.Signals), received
if received != signum:
raise Exception('received %s, not %s' % (received, signum))
''')
@@ -842,8 +864,14 @@ class PendingSignalsTests(unittest.TestCase):
def kill(signum):
os.kill(os.getpid(), signum)
+ def check_mask(mask):
+ for sig in mask:
+ assert isinstance(sig, signal.Signals), repr(sig)
+
def read_sigmask():
- return signal.pthread_sigmask(signal.SIG_BLOCK, [])
+ sigmask = signal.pthread_sigmask(signal.SIG_BLOCK, [])
+ check_mask(sigmask)
+ return sigmask
signum = signal.SIGUSR1
@@ -852,6 +880,7 @@ class PendingSignalsTests(unittest.TestCase):
# Unblock SIGUSR1 (and copy the old mask) to test our signal handler
old_mask = signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
+ check_mask(old_mask)
try:
kill(signum)
except ZeroDivisionError:
@@ -861,11 +890,13 @@ class PendingSignalsTests(unittest.TestCase):
# Block and then raise SIGUSR1. The signal is blocked: the signal
# handler is not called, and the signal is now pending
- signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
+ mask = signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
+ check_mask(mask)
kill(signum)
# Check the new mask
blocked = read_sigmask()
+ check_mask(blocked)
if signum not in blocked:
raise Exception("%s not in %s" % (signum, blocked))
if old_mask ^ blocked != {signum}:
@@ -928,7 +959,7 @@ class PendingSignalsTests(unittest.TestCase):
def test_main():
try:
- support.run_unittest(PosixTests, InterProcessSignalTests,
+ support.run_unittest(GenericTests, PosixTests, InterProcessSignalTests,
WakeupFDTests, WakeupSignalTests,
SiginterruptTest, ItimerTest, WindowsSignalTests,
PendingSignalsTests)