<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>