Commit 8df44277 authored by Jason Madden's avatar Jason Madden

Fix #805. Make reload(site) work w/gevent imported

Python 2 issue only.

Allow setting attributes on sys.modules['gevent.signal']; they go to the
gevent/signal.py module for symmetry with getattr and dir.

Reloading results in leaks so don't bother checking for them.
parent aaccf2d3
...@@ -68,7 +68,8 @@ Stdlib Compatibility ...@@ -68,7 +68,8 @@ Stdlib Compatibility
- :meth:`gevent.select.poll.poll` returns an event with - :meth:`gevent.select.poll.poll` returns an event with
``POLLNVAL`` for registered fds that are invalid. Previously it ``POLLNVAL`` for registered fds that are invalid. Previously it
would tend to report both read and write events. would tend to report both read and write events.
- Python 2: ``reload(site)`` no longer fails with a ``TypeError`` if
gevent has been imported. Reported in :issue:`805` by Jake Hilton.
Other Changes Other Changes
------------- -------------
...@@ -83,7 +84,8 @@ Other Changes ...@@ -83,7 +84,8 @@ Other Changes
timestamp. See :issue:`137`. timestamp. See :issue:`137`.
- Add :class:`gevent.threadpool.ThreadPoolExecutor` (a - Add :class:`gevent.threadpool.ThreadPoolExecutor` (a
:class:`concurrent.futures.ThreadPoolExecutor` variant that always :class:`concurrent.futures.ThreadPoolExecutor` variant that always
uses native threads) on platforms that have ``concurrent.futures`` uses native threads even when the system has been monkey-patched)
on platforms that have ``concurrent.futures``
available (Python 3 and Python 2 with the ``futures`` backport available (Python 3 and Python 2 with the ``futures`` backport
installed). This is helpful for, e.g., grpc. Reported in installed). This is helpful for, e.g., grpc. Reported in
:issue:`786` by Markus Padourek. :issue:`786` by Markus Padourek.
......
...@@ -85,9 +85,10 @@ class _signal_metaclass(type): ...@@ -85,9 +85,10 @@ class _signal_metaclass(type):
return getattr(_signal_module, name) return getattr(_signal_module, name)
def __setattr__(cls, name, value): def __setattr__(cls, name, value):
# Because we can't know whether to try to go to the module # For symmetry with getattr and dir, pass all
# or the class, we don't allow setting an attribute after the fact # attribute setting on to the module. (This makes
raise TypeError("Cannot set attribute") # reloading work, see issue #805)
setattr(_signal_module, name, value)
def __instancecheck__(cls, instance): def __instancecheck__(cls, instance):
return isinstance(instance, _signal_class) return isinstance(instance, _signal_class)
......
...@@ -58,13 +58,20 @@ PLATFORM_SPECIFIC_SUFFIXES = ['2', '279', '3'] ...@@ -58,13 +58,20 @@ PLATFORM_SPECIFIC_SUFFIXES = ['2', '279', '3']
if sys.platform.startswith('win'): if sys.platform.startswith('win'):
PLATFORM_SPECIFIC_SUFFIXES.append('posix') PLATFORM_SPECIFIC_SUFFIXES.append('posix')
PY2 = None
PY3 = None
PY34 = None
NON_APPLICABLE_SUFFIXES = [] NON_APPLICABLE_SUFFIXES = []
if sys.version_info[0] == 3: if sys.version_info[0] == 3:
# Python 3 # Python 3
NON_APPLICABLE_SUFFIXES.extend(('2', '279')) NON_APPLICABLE_SUFFIXES.extend(('2', '279'))
PY2 = False PY2 = False
PY3 = True PY3 = True
if sys.version_info[0] == 2: if sys.version_info[1] >= 4:
PY34 = True
elif sys.version_info[0] == 2:
# Any python 2 # Any python 2
PY3 = False PY3 = False
PY2 = True PY2 = True
...@@ -73,6 +80,7 @@ if sys.version_info[0] == 2: ...@@ -73,6 +80,7 @@ if sys.version_info[0] == 2:
or (sys.version_info[1] == 7 and sys.version_info[2] < 9)): or (sys.version_info[1] == 7 and sys.version_info[2] < 9)):
# Python 2, < 2.7.9 # Python 2, < 2.7.9
NON_APPLICABLE_SUFFIXES.append('279') NON_APPLICABLE_SUFFIXES.append('279')
if sys.platform.startswith('win'): if sys.platform.startswith('win'):
NON_APPLICABLE_SUFFIXES.append("posix") NON_APPLICABLE_SUFFIXES.append("posix")
# This is intimately tied to FileObjectPosix # This is intimately tied to FileObjectPosix
......
...@@ -18,7 +18,7 @@ if hasattr(signal, 'SIGALRM'): ...@@ -18,7 +18,7 @@ if hasattr(signal, 'SIGALRM'):
error_fatal = False error_fatal = False
__timeout__ = 5 __timeout__ = 5
def test(self): def test_alarm(self):
sig = gevent.signal(signal.SIGALRM, raise_Expected) sig = gevent.signal(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
...@@ -41,6 +41,31 @@ if hasattr(signal, 'SIGALRM'): ...@@ -41,6 +41,31 @@ if hasattr(signal, 'SIGALRM'):
finally: finally:
sig.cancel() sig.cancel()
@greentest.ignores_leakcheck
def test_reload(self):
# The site module tries to set attributes
# on all the modules that are loaded (specifically, __file__).
# If gevent.signal is loaded, and is our compatibility shim,
# this used to fail on Python 2: sys.modules['gevent.signal'] has no
# __loader__ attribute, so site.py's main() function tries to do
# gevent.signal.__file__ = os.path.abspath(gevent.signal.__file__), which
# used to not be allowed. (Under Python 3, __loader__ is present so this
# doesn't happen). See
# https://github.com/gevent/gevent/issues/805
import gevent.signal # make sure it's in sys.modules pylint:disable=redefined-outer-name
assert gevent.signal
import site
if greentest.PY34:
from importlib import reload as reload_module
elif greentest.PY3:
from imp import reload as reload_module
else:
# builtin on py2
reload_module = reload # pylint:disable=undefined-variable
reload_module(site)
if __name__ == '__main__': if __name__ == '__main__':
greentest.main() greentest.main()
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