<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Fri, Apr 4, 2014 at 10:12 AM, Brett Cannon <span dir="ltr"><<a href="mailto:brett@python.org" target="_blank">brett@python.org</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr">This broke compilation on at least OS X, but I'm willing to bet for all UNIX-based systems. I have a fix in the works.</div>
</blockquote><div><br></div><div>Fix is in rev <a href="http://hg.python.org/cpython/rev/c6e63bb132fb" target="_blank" style="font-size:13px;font-family:arial,sans-serif">c6e63bb132fb</a>.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div class="gmail_extra"><br><br><div class="gmail_quote"><div><div class="h5">On Fri, Apr 4, 2014 at 9:34 AM, giampaolo.rodola <span dir="ltr"><<a href="mailto:python-checkins@python.org" target="_blank">python-checkins@python.org</a>></span> wrote:<br>
</div></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div><div class="h5"><a href="http://hg.python.org/cpython/rev/c9239171e429" target="_blank">http://hg.python.org/cpython/rev/c9239171e429</a><br>
changeset: 90128:c9239171e429<br>
user: Giampaolo Rodola' <<a href="mailto:g.rodola@gmail.com" target="_blank">g.rodola@gmail.com</a>><br>
date: Fri Apr 04 15:34:17 2014 +0200<br>
summary:<br>
fix #21076: turn signal module constants into enums<br>
<br>
files:<br>
Doc/library/signal.rst | 10 +++<br>
Doc/whatsnew/3.5.rst | 5 +<br>
Lib/signal.py | 84 ++++++++++++++++++++++++++++<br>
Lib/test/test_doctest.py | 2 +-<br>
Lib/test/test_signal.py | 39 +++++++++++-<br>
Modules/signalmodule.c | 4 +-<br>
PC/config.c | 2 +-<br>
7 files changed, 138 insertions(+), 8 deletions(-)<br>
<br>
<br>
diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst<br>
--- a/Doc/library/signal.rst<br>
+++ b/Doc/library/signal.rst<br>
@@ -65,6 +65,16 @@<br>
Module contents<br>
---------------<br>
<br>
+.. versionchanged:: 3.5<br>
+ signal (SIG*), handler (:const:`SIG_DFL`, :const:`SIG_IGN`) and sigmask<br>
+ (:const:`SIG_BLOCK`, :const:`SIG_UNBLOCK`, :const:`SIG_SETMASK`)<br>
+ related constants listed below were turned into<br>
+ :class:`enums <enum.IntEnum>`.<br>
+ :func:`getsignal`, :func:`pthread_sigmask`, :func:`sigpending` and<br>
+ :func:`sigwait` functions return human-readable<br>
+ :class:`enums <enum.IntEnum>`.<br>
+<br>
+<br>
The variables defined in the :mod:`signal` module are:<br>
<br>
<br>
diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst<br>
--- a/Doc/whatsnew/3.5.rst<br>
+++ b/Doc/whatsnew/3.5.rst<br>
@@ -134,6 +134,11 @@<br>
Improved Modules<br>
================<br>
<br>
+* Different constants of :mod:`signal` module are now enumeration values using<br>
+ the :mod:`enum` module. This allows meaningful names to be printed during<br>
+ debugging, instead of integer “magic numbers”. (contribute by Giampaolo<br>
+ Rodola' in :issue:`21076`)<br>
+<br>
* :class:`xmlrpc.client.ServerProxy` is now a :term:`context manager`<br>
(contributed by Claudiu Popa in :issue:`20627`).<br>
<br>
diff --git a/Lib/signal.py b/Lib/signal.py<br>
new file mode 100644<br>
--- /dev/null<br>
+++ b/Lib/signal.py<br>
@@ -0,0 +1,84 @@<br>
+import _signal<br>
+from _signal import *<br>
+from functools import wraps as _wraps<br>
+from enum import IntEnum as _IntEnum<br>
+<br>
+_globals = globals()<br>
+<br>
+Signals = _IntEnum(<br>
+ 'Signals',<br>
+ {name: value for name, value in _globals.items()<br>
+ if name.isupper()<br>
+ and (name.startswith('SIG') and not name.startswith('SIG_'))<br>
+ or name.startswith('CTRL_')})<br>
+<br>
+class Handlers(_IntEnum):<br>
+ SIG_DFL = _signal.SIG_DFL<br>
+ SIG_IGN = _signal.SIG_IGN<br>
+<br>
+_globals.update(Signals.__members__)<br>
+_globals.update(Handlers.__members__)<br>
+<br>
+if 'pthread_sigmask' in _globals:<br>
+ class Sigmasks(_IntEnum):<br>
+ SIG_BLOCK = _signal.SIG_BLOCK<br>
+ SIG_UNBLOCK = _signal.SIG_UNBLOCK<br>
+ SIG_SETMASK = _signal.SIG_SETMASK<br>
+<br>
+ _globals.update(Sigmasks.__members__)<br>
+<br>
+<br>
+def _int_to_enum(value, enum_klass):<br>
+ """Convert a numeric value to an IntEnum member.<br>
+ If it's not a known member, return the numeric value itself.<br>
+ """<br>
+ try:<br>
+ return enum_klass(value)<br>
+ except ValueError:<br>
+ return value<br>
+<br>
+<br>
+def _enum_to_int(value):<br>
+ """Convert an IntEnum member to a numeric value.<br>
+ If it's not a IntEnum member return the value itself.<br>
+ """<br>
+ try:<br>
+ return int(value)<br>
+ except (ValueError, TypeError):<br>
+ return value<br>
+<br>
+<br>
+@_wraps(_signal.signal)<br>
+def signal(signalnum, handler):<br>
+ handler = _signal.signal(_enum_to_int(signalnum), _enum_to_int(handler))<br>
+ return _int_to_enum(handler, Handlers)<br>
+<br>
+<br>
+@_wraps(_signal.getsignal)<br>
+def getsignal(signalnum):<br>
+ handler = _signal.getsignal(signalnum)<br>
+ return _int_to_enum(handler, Handlers)<br>
+<br>
+<br>
+if 'pthread_sigmask' in _globals:<br>
+ @_wraps(_signal.pthread_sigmask)<br>
+ def pthread_sigmask(how, mask):<br>
+ sigs_set = _signal.pthread_sigmask(how, mask)<br>
+ return set(_int_to_enum(x, Signals) for x in sigs_set)<br>
+ pthread_sigmask.__doc__ = _signal.pthread_sigmask.__doc__<br>
+<br>
+<br>
+@_wraps(_signal.sigpending)<br>
+def sigpending():<br>
+ sigs = _signal.sigpending()<br>
+ return set(_int_to_enum(x, Signals) for x in sigs)<br>
+<br>
+<br>
+if 'sigwait' in _globals:<br>
+ @_wraps(_signal.sigwait)<br>
+ def sigwait(sigset):<br>
+ retsig = _signal.sigwait(sigset)<br>
+ return _int_to_enum(retsig, Signals)<br>
+ sigwait.__doc__ = _signal.sigwait<br>
+<br>
+del _globals, _wraps<br>
diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py<br>
--- a/Lib/test/test_doctest.py<br>
+++ b/Lib/test/test_doctest.py<br>
@@ -2897,7 +2897,7 @@<br>
<br>
def test_main():<br>
# Check the doctest cases in doctest itself:<br>
- support.run_doctest(doctest, verbosity=True)<br>
+ ret = support.run_doctest(doctest, verbosity=True)<br>
# Check the doctest cases defined here:<br>
from test import test_doctest<br>
support.run_doctest(test_doctest, verbosity=True)<br>
diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py<br>
--- a/Lib/test/test_signal.py<br>
+++ b/Lib/test/test_signal.py<br>
@@ -1,6 +1,7 @@<br>
import unittest<br>
from test import support<br>
from contextlib import closing<br>
+import enum<br>
import gc<br>
import pickle<br>
import select<br>
@@ -39,6 +40,22 @@<br>
return None<br>
<br>
<br>
+class GenericTests(unittest.TestCase):<br>
+<br>
+ def test_enums(self):<br>
+ for name in dir(signal):<br>
+ sig = getattr(signal, name)<br>
+ if name in {'SIG_DFL', 'SIG_IGN'}:<br>
+ self.assertIsInstance(sig, signal.Handlers)<br>
+ elif name in {'SIG_BLOCK', 'SIG_UNBLOCK', 'SIG_SETMASK'}:<br>
+ self.assertIsInstance(sig, signal.Sigmasks)<br>
+ elif name.startswith('SIG') and not name.startswith('SIG_'):<br>
+ self.assertIsInstance(sig, signal.Signals)<br>
+ elif name.startswith('CTRL_'):<br>
+ self.assertIsInstance(sig, signal.Signals)<br>
+ self.assertEqual(sys.platform, "win32")<br>
+<br>
+<br>
@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")<br>
class InterProcessSignalTests(unittest.TestCase):<br>
MAX_DURATION = 20 # Entire test should last at most 20 sec.<br>
@@ -195,6 +212,7 @@<br>
<br>
def test_getsignal(self):<br>
hup = signal.signal(signal.SIGHUP, self.trivial_signal_handler)<br>
+ self.assertIsInstance(hup, signal.Handlers)<br>
self.assertEqual(signal.getsignal(signal.SIGHUP),<br>
self.trivial_signal_handler)<br>
signal.signal(signal.SIGHUP, hup)<br>
@@ -271,7 +289,7 @@<br>
<br>
os.close(read)<br>
os.close(write)<br>
- """.format(signals, ordered, test_body)<br>
+ """.format(tuple(map(int, signals)), ordered, test_body)<br>
<br>
assert_python_ok('-c', code)<br>
<br>
@@ -604,6 +622,8 @@<br>
signal.pthread_sigmask(signal.SIG_BLOCK, [signum])<br>
os.kill(os.getpid(), signum)<br>
pending = signal.sigpending()<br>
+ for sig in pending:<br>
+ assert isinstance(sig, signal.Signals), repr(pending)<br>
if pending != {signum}:<br>
raise Exception('%s != {%s}' % (pending, signum))<br>
try:<br>
@@ -660,6 +680,7 @@<br>
code = '''if 1:<br>
import signal<br>
import sys<br>
+ from signal import Signals<br>
<br>
def handler(signum, frame):<br>
1/0<br>
@@ -702,6 +723,7 @@<br>
def test(signum):<br>
signal.alarm(1)<br>
received = signal.sigwait([signum])<br>
+ assert isinstance(received, signal.Signals), received<br>
if received != signum:<br>
raise Exception('received %s, not %s' % (received, signum))<br>
''')<br>
@@ -842,8 +864,14 @@<br>
def kill(signum):<br>
os.kill(os.getpid(), signum)<br>
<br>
+ def check_mask(mask):<br>
+ for sig in mask:<br>
+ assert isinstance(sig, signal.Signals), repr(sig)<br>
+<br>
def read_sigmask():<br>
- return signal.pthread_sigmask(signal.SIG_BLOCK, [])<br>
+ sigmask = signal.pthread_sigmask(signal.SIG_BLOCK, [])<br>
+ check_mask(sigmask)<br>
+ return sigmask<br>
<br>
signum = signal.SIGUSR1<br>
<br>
@@ -852,6 +880,7 @@<br>
<br>
# Unblock SIGUSR1 (and copy the old mask) to test our signal handler<br>
old_mask = signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])<br>
+ check_mask(old_mask)<br>
try:<br>
kill(signum)<br>
except ZeroDivisionError:<br>
@@ -861,11 +890,13 @@<br>
<br>
# Block and then raise SIGUSR1. The signal is blocked: the signal<br>
# handler is not called, and the signal is now pending<br>
- signal.pthread_sigmask(signal.SIG_BLOCK, [signum])<br>
+ mask = signal.pthread_sigmask(signal.SIG_BLOCK, [signum])<br>
+ check_mask(mask)<br>
kill(signum)<br>
<br>
# Check the new mask<br>
blocked = read_sigmask()<br>
+ check_mask(blocked)<br>
if signum not in blocked:<br>
raise Exception("%s not in %s" % (signum, blocked))<br>
if old_mask ^ blocked != {signum}:<br>
@@ -928,7 +959,7 @@<br>
<br>
def test_main():<br>
try:<br>
- support.run_unittest(PosixTests, InterProcessSignalTests,<br>
+ support.run_unittest(GenericTests, PosixTests, InterProcessSignalTests,<br>
WakeupFDTests, WakeupSignalTests,<br>
SiginterruptTest, ItimerTest, WindowsSignalTests,<br>
PendingSignalsTests)<br>
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c<br>
--- a/Modules/signalmodule.c<br>
+++ b/Modules/signalmodule.c<br>
@@ -967,7 +967,7 @@<br>
};<br>
<br>
PyMODINIT_FUNC<br>
-PyInit_signal(void)<br>
+PyInit__signal(void)<br>
{<br>
PyObject *m, *d, *x;<br>
int i;<br>
@@ -1380,7 +1380,7 @@<br>
void<br>
PyOS_InitInterrupts(void)<br>
{<br>
- PyObject *m = PyImport_ImportModule("signal");<br>
+ PyObject *m = PyImport_ImportModule("_signal");<br>
if (m) {<br>
Py_DECREF(m);<br>
}<br>
diff --git a/PC/config.c b/PC/config.c<br>
--- a/PC/config.c<br>
+++ b/PC/config.c<br>
@@ -19,7 +19,7 @@<br>
extern PyObject* PyInit__md5(void);<br>
extern PyObject* PyInit_nt(void);<br>
extern PyObject* PyInit__operator(void);<br>
-extern PyObject* PyInit_signal(void);<br>
+extern PyObject* PyInit__signal(void);<br>
extern PyObject* PyInit__sha1(void);<br>
extern PyObject* PyInit__sha256(void);<br>
extern PyObject* PyInit__sha512(void);<br>
<span><font color="#888888"><br>
--<br>
Repository URL: <a href="http://hg.python.org/cpython" target="_blank">http://hg.python.org/cpython</a><br>
</font></span><br></div></div>_______________________________________________<br>
Python-checkins mailing list<br>
<a href="mailto:Python-checkins@python.org" target="_blank">Python-checkins@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-checkins" target="_blank">https://mail.python.org/mailman/listinfo/python-checkins</a><br>
<br></blockquote></div><br></div>
</blockquote></div><br></div></div>