[Python-checkins] cpython (merge default -> default): merge along w/ fix for issue #2107 (commit c9239171e429)

brett.cannon python-checkins at python.org
Fri Apr 4 16:20:41 CEST 2014


http://hg.python.org/cpython/rev/c6e63bb132fb
changeset:   90136:c6e63bb132fb
parent:      90135:a11ec7aaac10
parent:      90132:4acff7c4bd02
user:        Brett Cannon <brett at python.org>
date:        Fri Apr 04 10:20:28 2014 -0400
summary:
  merge along w/ fix for issue #2107 (commit c9239171e429)

files:
  Doc/library/signal.rst   |  10 +++
  Doc/whatsnew/3.5.rst     |   5 +
  Lib/signal.py            |  84 ++++++++++++++++++++++++++++
  Lib/test/test_doctest.py |   2 +-
  Lib/test/test_signal.py  |  39 +++++++++++-
  Modules/signalmodule.c   |   6 +-
  PC/config.c              |   2 +-
  7 files changed, 139 insertions(+), 9 deletions(-)


diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst
--- a/Doc/library/signal.rst
+++ b/Doc/library/signal.rst
@@ -65,6 +65,16 @@
 Module contents
 ---------------
 
+.. versionchanged:: 3.5
+   signal (SIG*), handler (:const:`SIG_DFL`, :const:`SIG_IGN`) and sigmask
+   (:const:`SIG_BLOCK`, :const:`SIG_UNBLOCK`, :const:`SIG_SETMASK`)
+   related constants listed below were turned into
+   :class:`enums <enum.IntEnum>`.
+   :func:`getsignal`, :func:`pthread_sigmask`, :func:`sigpending` and
+   :func:`sigwait` functions return human-readable
+   :class:`enums <enum.IntEnum>`.
+
+
 The variables defined in the :mod:`signal` module are:
 
 
diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst
--- a/Doc/whatsnew/3.5.rst
+++ b/Doc/whatsnew/3.5.rst
@@ -134,6 +134,11 @@
 Improved Modules
 ================
 
+* Different constants of :mod:`signal` module are now enumeration values using
+  the :mod:`enum` module. This allows meaningful names to be printed during
+  debugging, instead of integer “magic numbers”. (contribute by Giampaolo
+  Rodola' in :issue:`21076`)
+
 * :class:`xmlrpc.client.ServerProxy` is now a :term:`context manager`
   (contributed by Claudiu Popa in :issue:`20627`).
 
diff --git a/Lib/signal.py b/Lib/signal.py
new file mode 100644
--- /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
+
+
+ at _wraps(_signal.signal)
+def signal(signalnum, handler):
+    handler = _signal.signal(_enum_to_int(signalnum), _enum_to_int(handler))
+    return _int_to_enum(handler, Handlers)
+
+
+ at _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__
+
+
+ at _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
--- a/Lib/test/test_doctest.py
+++ b/Lib/test/test_doctest.py
@@ -2897,7 +2897,7 @@
 
 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
--- 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 @@
         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 @@
 
     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 @@
 
         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 @@
             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 @@
         code = '''if 1:
         import signal
         import sys
+        from signal import Signals
 
         def handler(signum, frame):
             1/0
@@ -702,6 +723,7 @@
         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 @@
         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 @@
 
         # 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 @@
 
         # 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 @@
 
 def test_main():
     try:
-        support.run_unittest(PosixTests, InterProcessSignalTests,
+        support.run_unittest(GenericTests, PosixTests, InterProcessSignalTests,
                              WakeupFDTests, WakeupSignalTests,
                              SiginterruptTest, ItimerTest, WindowsSignalTests,
                              PendingSignalsTests)
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
--- a/Modules/signalmodule.c
+++ b/Modules/signalmodule.c
@@ -956,7 +956,7 @@
 
 static struct PyModuleDef signalmodule = {
     PyModuleDef_HEAD_INIT,
-    "signal",
+    "_signal",
     module_doc,
     -1,
     signal_methods,
@@ -967,7 +967,7 @@
 };
 
 PyMODINIT_FUNC
-PyInit_signal(void)
+PyInit__signal(void)
 {
     PyObject *m, *d, *x;
     int i;
@@ -1380,7 +1380,7 @@
 void
 PyOS_InitInterrupts(void)
 {
-    PyObject *m = PyImport_ImportModule("signal");
+    PyObject *m = PyImport_ImportModule("_signal");
     if (m) {
         Py_DECREF(m);
     }
diff --git a/PC/config.c b/PC/config.c
--- a/PC/config.c
+++ b/PC/config.c
@@ -19,7 +19,7 @@
 extern PyObject* PyInit__md5(void);
 extern PyObject* PyInit_nt(void);
 extern PyObject* PyInit__operator(void);
-extern PyObject* PyInit_signal(void);
+extern PyObject* PyInit__signal(void);
 extern PyObject* PyInit__sha1(void);
 extern PyObject* PyInit__sha256(void);
 extern PyObject* PyInit__sha512(void);

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list