Commit 591978a4 authored by Jason Madden's avatar Jason Madden

Make gevent.signal function as a callable, no matter the order of imports. Fixes #648.

parent ea62d6c6
......@@ -153,8 +153,30 @@ Working with muliple processes
Signals
-------
.. autofunction:: signal
.. function:: signal(signalnum, handler, *args, **kwargs)
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
This is an alias for ``gevent.hub.signal``, 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.
.. This is also in the docstring of gevent.hub.signal, which is the
actual callable invoked
Timeouts
========
......
......@@ -18,7 +18,7 @@ _version_info = namedtuple('version_info',
version_info = _version_info(1, 1, 0, 'beta', '5')
#: The human-readable PEP 440 version identifier
__version__ = '1.1b5dev0'
__version__ = '1.1b5.dev0'
__all__ = ['get_hub',
......@@ -45,20 +45,73 @@ import sys
if sys.platform == 'win32':
import socket # trigger WSAStartup call
del socket
del sys
from gevent.hub import get_hub, iwait, wait, PYPY
from gevent.greenlet import Greenlet, joinall, killall
spawn = Greenlet.spawn
spawn_later = Greenlet.spawn_later
from gevent.timeout import Timeout, with_timeout
from gevent.hub import getcurrent, GreenletExit, spawn_raw, sleep, idle, kill, signal, reinit
from gevent.hub import getcurrent, GreenletExit, spawn_raw, sleep, idle, kill, reinit
try:
from gevent.os import fork
except ImportError:
__all__.remove('fork')
# See https://github.com/gevent/gevent/issues/648
# A temporary backwards compatibility shim to enable users to continue
# to treat 'from gevent import signal' as a callable, to matter whether
# the 'gevent.signal' module has been imported first
from gevent.hub import signal as _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__(self, name):
return getattr(_signal_module, name)
def __setattr__(self, name, value):
# Because we can't know whether to try to go to the module
# or the class, we don't allow setting an attribute after the fact
raise TypeError("Cannot set attribute")
def __instancecheck__(self, instance):
return isinstance(instance, _signal_class)
def __dir__(self):
return dir(_signal_module)
class signal(object):
__doc__ = _signal_module.__doc__
def __new__(self, *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
# py2exe. see https://github.com/gevent/gevent/issues/181
......
......@@ -198,6 +198,9 @@ class signal(object):
are used (as they are by default with os.fork).
"""
# XXX: This is manually documented in gevent.rst while it is aliased in
# the gevent module.
greenlet_class = None
def __init__(self, signalnum, handler, *args, **kwargs):
......
from __future__ import print_function
import sys
# Using a direct import of signal (deprecated).
# We are also called from test__core_loop_run_sig_mod.py,
# 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()
......
import sys
import types
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.
from gevent.hub import signal as hub_signal
from gevent import signal
assert gevent.signal is hub_signal
assert gevent.signal is signal
assert hasattr(gevent.signal, 'signal')
s = signal(2, sys.stderr.write, 'INTERRUPT')
assert isinstance(s, signal)
assert isinstance(s, hub_signal)
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