On Fri, Apr 4, 2014 at 10:12 AM, Brett Cannon <br...@python.org> wrote:
> 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. > Fix is in rev c6e63bb132fb <http://hg.python.org/cpython/rev/c6e63bb132fb>. > > > On Fri, Apr 4, 2014 at 9:34 AM, giampaolo.rodola < > python-check...@python.org> wrote: > >> http://hg.python.org/cpython/rev/c9239171e429 >> changeset: 90128:c9239171e429 >> user: Giampaolo Rodola' <g.rod...@gmail.com> >> date: Fri Apr 04 15:34:17 2014 +0200 >> summary: >> fix #21076: turn signal module constants into enums >> >> 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 | 4 +- >> PC/config.c | 2 +- >> 7 files changed, 138 insertions(+), 8 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 >> + >> + >> +@_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 >> --- 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 >> @@ -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 >> >> _______________________________________________ >> Python-checkins mailing list >> python-check...@python.org >> https://mail.python.org/mailman/listinfo/python-checkins >> >> >
_______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com