Commit c307b070 authored by Jason Madden's avatar Jason Madden

Remove the deprecated magic proxy gevent.signal.

Leave behind the actual module gevent.signal, and the callable gevent.signal_handler.

Fixes #1596
parent 33e10d8e
...@@ -49,6 +49,15 @@ Library and Dependency Updates ...@@ -49,6 +49,15 @@ Library and Dependency Updates
because of the limited amount of actual allocation that gets done because of the limited amount of actual allocation that gets done
this is not expected to be a bottleneck. this is not expected to be a bottleneck.
Potentially Breaking Changes
----------------------------
- Remove the magic proxy object ``gevent.signal``. This served as both
a deprecated alias of `gevent.signal_handler` *and* the module
`gevent.signal`. This made it confusing to humans and static
analysis tools alike. The alias was deprecated since gevent 1.1b4.
See :issue:`1596`.
Other Other
----- -----
...@@ -78,6 +87,7 @@ Other ...@@ -78,6 +87,7 @@ Other
before the gevent resolver was initialized. Reported in before the gevent resolver was initialized. Reported in
:issue:`1526` by Chris Utz and Josh Zuech. :issue:`1526` by Chris Utz and Josh Zuech.
1.5a3 (2020-01-01) 1.5a3 (2020-01-01)
================== ==================
......
...@@ -103,34 +103,7 @@ Working with multiple processes ...@@ -103,34 +103,7 @@ Working with multiple processes
Signals Signals
======= =======
.. function:: signal_handler(signalnum, handler, *args, **kwargs) .. autofunction:: signal_handler
Call the *handler* with the *args* and *kwargs* when the process
receives the signal *signalnum*.
The *handler* will be run in a new greenlet when the signal is delivered.
This returns an object with the useful method ``cancel``, which, when called,
will prevent future deliveries of *signalnum* from calling *handler*.
.. note::
This may not operate correctly with SIGCHLD if libev child watchers
are used (as they are by default with :func:`gevent.os.fork`).
.. versionchanged:: 1.1b4
``gevent.signal`` is an alias for this function, included for
backwards compatibility; the new module :doc:`gevent.signal <gevent.signal>`
is replacing this name. This alias will be removed in a
future release.
.. versionchanged:: 1.2a1
The *handler* is required to be callable at construction time.
.. This is also in the docstring of gevent.hub.signal, which is the
actual callable invoked
Timeouts Timeouts
======== ========
......
...@@ -97,8 +97,8 @@ def main(): ...@@ -97,8 +97,8 @@ def main():
dest = parse_address(args[1]) dest = parse_address(args[1])
server = PortForwarder(source, dest) server = PortForwarder(source, dest)
log('Starting port forwarder %s:%s -> %s:%s', *(server.address[:2] + dest)) log('Starting port forwarder %s:%s -> %s:%s', *(server.address[:2] + dest))
gevent.signal(signal.SIGTERM, server.close) gevent.signal_handler(signal.SIGTERM, server.close)
gevent.signal(signal.SIGINT, server.close) gevent.signal_handler(signal.SIGINT, server.close)
server.start() server.start()
gevent.wait() gevent.wait()
......
...@@ -46,7 +46,6 @@ __all__ = [ ...@@ -46,7 +46,6 @@ __all__ = [
'killall', 'killall',
'reinit', 'reinit',
'setswitchinterval', 'setswitchinterval',
'signal', # deprecated
'signal_handler', 'signal_handler',
'sleep', 'sleep',
'spawn', 'spawn',
...@@ -100,60 +99,11 @@ try: ...@@ -100,60 +99,11 @@ try:
except ImportError: except ImportError:
__all__.remove('fork') __all__.remove('fork')
# See https://github.com/gevent/gevent/issues/648 # This used to be available as gevent.signal; that broke in 1.1b4 but
# A temporary backwards compatibility shim to enable users to continue # a temporary alias was added (See
# to treat 'from gevent import signal' as a callable, to matter whether # https://github.com/gevent/gevent/issues/648). It was ugly and complex and
# the 'gevent.signal' module has been imported first # caused confusion, so it was removed in 1.5. See https://github.com/gevent/gevent/issues/1529
from gevent.hub import signal as _signal_class from gevent.hub import signal as signal_handler
signal_handler = _signal_class
from gevent import signal as _signal_module
# The object 'gevent.signal' must:
# - be callable, returning a gevent.hub.signal;
# - answer True to isinstance(gevent.signal(...), gevent.signal);
# - answer True to isinstance(gevent.signal(...), gevent.hub.signal)
# - have all the attributes of the module 'gevent.signal';
# - answer True to isinstance(gevent.signal, types.ModuleType) (optional)
# The only way to do this is to use a metaclass, an instance of which (a class)
# is put in sys.modules and is substituted for gevent.hub.signal.
# This handles everything except the last one.
class _signal_metaclass(type):
def __getattr__(cls, name):
return getattr(_signal_module, name)
def __setattr__(cls, name, value):
setattr(_signal_module, name, value)
def __instancecheck__(cls, instance):
return isinstance(instance, _signal_class)
def __dir__(cls):
return dir(_signal_module)
class signal(object):
__doc__ = _signal_module.__doc__
def __new__(cls, *args, **kwargs):
return _signal_class(*args, **kwargs)
# The metaclass is applied after the class declaration
# for Python 2/3 compatibility
signal = _signal_metaclass(str("signal"),
(),
dict(signal.__dict__))
sys.modules['gevent.signal'] = signal
sys.modules['gevent.hub'].signal = signal
del sys
# the following makes hidden imports visible to freezing tools like # the following makes hidden imports visible to freezing tools like
# py2exe. see https://github.com/gevent/gevent/issues/181 # py2exe. see https://github.com/gevent/gevent/issues/181
......
...@@ -213,25 +213,32 @@ def kill(greenlet, exception=GreenletExit): ...@@ -213,25 +213,32 @@ def kill(greenlet, exception=GreenletExit):
class signal(object): class signal(object):
""" """
signal_handler(signalnum, handler, *args, **kwargs) -> object
Call the *handler* with the *args* and *kwargs* when the process Call the *handler* with the *args* and *kwargs* when the process
receives the signal *signalnum*. receives the signal *signalnum*.
The *handler* will be run in a new greenlet when the signal is delivered. The *handler* will be run in a new greenlet when the signal is
delivered.
This returns an object with the useful method ``cancel``, which, when called, This returns an object with the useful method ``cancel``, which,
will prevent future deliveries of *signalnum* from calling *handler*. when called, will prevent future deliveries of *signalnum* from
calling *handler*.
.. note:: .. note::
This may not operate correctly with SIGCHLD if libev child watchers This may not operate correctly with ``SIGCHLD`` if libev child
are used (as they are by default with os.fork). watchers are used (as they are by default with
`gevent.os.fork`). See :mod:`gevent.signal` for a more
general purpose solution.
.. versionchanged:: 1.2a1 .. versionchanged:: 1.2a1
The ``handler`` argument is required to be callable at construction time.
"""
# XXX: This is manually documented in gevent.rst while it is aliased in The ``handler`` argument is required to
# the gevent module. be callable at construction time.
"""
# This is documented as a function, not a class,
# so we're free to change implementation details.
greenlet_class = None greenlet_class = None
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
Cooperative implementation of special cases of :func:`signal.signal`. Cooperative implementation of special cases of :func:`signal.signal`.
This module is designed to work with libev's child watchers, as used This module is designed to work with libev's child watchers, as used
by default in :func:`gevent.os.fork` Note that each ``SIGCHLD`` handler by default in :func:`gevent.os.fork` Note that each ``SIGCHLD``
will be run in a new greenlet when the signal is delivered (just like handler will be run in a new greenlet when the signal is delivered
:class:`gevent.hub.signal`) (just like :class:`gevent.hub.signal`)
The implementations in this module are only monkey patched if The implementations in this module are only monkey patched if
:func:`gevent.os.waitpid` is being used (the default) and if :func:`gevent.os.waitpid` is being used (the default) and if
...@@ -12,6 +12,11 @@ The implementations in this module are only monkey patched if ...@@ -12,6 +12,11 @@ The implementations in this module are only monkey patched if
information on configuring this not to be the case for advanced uses. information on configuring this not to be the case for advanced uses.
.. versionadded:: 1.1b4 .. versionadded:: 1.1b4
.. versionchanged:: 1.5a4
Previously there was a backwards compatibility alias
``gevent.signal``, introduced in 1.1b4, that partly shadowed this
module, confusing humans and static analysis tools alike. That alias
has been removed. (See `gevent.signal_handler`.)
""" """
from __future__ import absolute_import from __future__ import absolute_import
......
from __future__ import print_function from __future__ import print_function
import sys import sys
# Using a direct import of signal (deprecated). from gevent import core
# We are also called from test__core_loop_run_sig_mod.py, from gevent import signal_handler as signal
# which has already done 'import gevent.signal' to be sure we work
# when the module has been imported.
from gevent import core, signal
loop = core.loop(default=False) loop = core.loop(default=False)
......
import sys
import gevent.signal
assert gevent.signal # Get gevent.signal as a module, make sure our backwards compatibility kicks in
import test__core_loop_run # this runs main tests, fails if signal() is not callable.
assert test__core_loop_run # pyflakes
from gevent.hub import signal as hub_signal
from gevent import signal as top_signal # pylint:disable=reimported
assert gevent.signal is hub_signal
assert gevent.signal is top_signal
assert hasattr(gevent.signal, 'signal')
s = top_signal(2, sys.stderr.write, 'INTERRUPT')
assert isinstance(s, top_signal)
assert isinstance(s, hub_signal)
...@@ -10,7 +10,7 @@ from gevent.testing.testcase import TimeAssertMixin ...@@ -10,7 +10,7 @@ from gevent.testing.testcase import TimeAssertMixin
SMALL_TICK = 0.05 SMALL_TICK = 0.05
# setting up signal does not affect join() # setting up signal does not affect join()
gevent.signal(1, lambda: None) # wouldn't work on windows gevent.signal_handler(1, lambda: None) # wouldn't work on windows
def repeated(func, repetitions=2): def repeated(func, repetitions=2):
......
...@@ -27,10 +27,11 @@ class TestSignal(greentest.TestCase): ...@@ -27,10 +27,11 @@ class TestSignal(greentest.TestCase):
__timeout__ = greentest.LARGE_TIMEOUT __timeout__ = greentest.LARGE_TIMEOUT
def test_handler(self): def test_handler(self):
self.assertRaises(TypeError, gevent.signal, signal.SIGALRM, 1) with self.assertRaises(TypeError):
gevent.signal_handler(signal.SIGALRM, 1)
def test_alarm(self): def test_alarm(self):
sig = gevent.signal(signal.SIGALRM, raise_Expected) sig = gevent.signal_handler(signal.SIGALRM, raise_Expected)
assert sig.ref is False, repr(sig.ref) assert sig.ref is False, repr(sig.ref)
sig.ref = True sig.ref = True
assert sig.ref is True assert sig.ref is True
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment