hubs: get_default_hub() on Windows broken by kqueue; Thanks to Paul Oppenheim

Fixes https://github.com/eventlet/eventlet/issues/38
+autopep8
This commit is contained in:
Sergey Shepelev
2013-07-02 18:29:48 +04:00
parent 747b753a20
commit b87ed20e8c
3 changed files with 99 additions and 35 deletions

View File

@@ -16,12 +16,13 @@ __all__ = ["use_hub", "get_hub", "get_default_hub", "trampoline"]
threading = patcher.original('threading') threading = patcher.original('threading')
_threadlocal = threading.local() _threadlocal = threading.local()
def get_default_hub(): def get_default_hub():
"""Select the default hub implementation based on what multiplexing """Select the default hub implementation based on what multiplexing
libraries are installed. The order that the hubs are tried is: libraries are installed. The order that the hubs are tried is:
* twistedr
* epoll * epoll
* kqueue
* poll * poll
* select * select
@@ -91,12 +92,14 @@ def use_hub(mod=None):
mod, found = entry.load(), True mod, found = entry.load(), True
break break
if not found: if not found:
mod = __import__('eventlet.hubs.' + mod, globals(), locals(), ['Hub']) mod = __import__(
'eventlet.hubs.' + mod, globals(), locals(), ['Hub'])
if hasattr(mod, 'Hub'): if hasattr(mod, 'Hub'):
_threadlocal.Hub = mod.Hub _threadlocal.Hub = mod.Hub
else: else:
_threadlocal.Hub = mod _threadlocal.Hub = mod
def get_hub(): def get_hub():
"""Get the current event hub singleton object. """Get the current event hub singleton object.
@@ -113,6 +116,8 @@ def get_hub():
return hub return hub
from eventlet import timeout from eventlet import timeout
def trampoline(fd, read=None, write=None, timeout=None, def trampoline(fd, read=None, write=None, timeout=None,
timeout_exc=timeout.Timeout): timeout_exc=timeout.Timeout):
"""Suspend the current coroutine until the given socket object or file """Suspend the current coroutine until the given socket object or file
@@ -133,7 +138,8 @@ def trampoline(fd, read=None, write=None, timeout=None,
hub = get_hub() hub = get_hub()
current = greenlet.getcurrent() current = greenlet.getcurrent()
assert hub.greenlet is not current, 'do not call blocking functions from the mainloop' assert hub.greenlet is not current, 'do not call blocking functions from the mainloop'
assert not (read and write), 'not allowed to trampoline for reading and writing' assert not (
read and write), 'not allowed to trampoline for reading and writing'
try: try:
fileno = fd.fileno() fileno = fd.fileno()
except AttributeError: except AttributeError:

View File

@@ -8,9 +8,15 @@ sleep = time.sleep
from eventlet.support import get_errno, clear_sys_exc_info from eventlet.support import get_errno, clear_sys_exc_info
from eventlet.hubs.hub import BaseHub, READ, WRITE, noop from eventlet.hubs.hub import BaseHub, READ, WRITE, noop
if getattr(select, 'kqueue', None) is None:
raise ImportError('No kqueue implementation found in select module')
FILTERS = {READ: select.KQ_FILTER_READ, FILTERS = {READ: select.KQ_FILTER_READ,
WRITE: select.KQ_FILTER_WRITE} WRITE: select.KQ_FILTER_WRITE}
class Hub(BaseHub): class Hub(BaseHub):
MAX_EVENTS = 100 MAX_EVENTS = 100

View File

@@ -2,6 +2,7 @@ from __future__ import with_statement
import sys import sys
from tests import LimitedTestCase, main, skip_with_pyevent, skip_if_no_itimer, skip_unless from tests import LimitedTestCase, main, skip_with_pyevent, skip_if_no_itimer, skip_unless
from tests.patcher_test import ProcessBase
import time import time
import eventlet import eventlet
from eventlet import hubs from eventlet import hubs
@@ -11,11 +12,15 @@ from eventlet.semaphore import Semaphore
from eventlet.support import greenlets from eventlet.support import greenlets
DELAY = 0.001 DELAY = 0.001
def noop(): def noop():
pass pass
class TestTimerCleanup(LimitedTestCase): class TestTimerCleanup(LimitedTestCase):
TEST_TIMEOUT = 2 TEST_TIMEOUT = 2
@skip_with_pyevent @skip_with_pyevent
def test_cancel_immediate(self): def test_cancel_immediate(self):
hub = hubs.get_hub() hub = hubs.get_hub()
@@ -30,7 +35,6 @@ class TestTimerCleanup(LimitedTestCase):
self.assert_less_than_equal(hub.get_timers_count(), 1000 + stimers) self.assert_less_than_equal(hub.get_timers_count(), 1000 + stimers)
self.assert_less_than_equal(hub.timers_canceled, 1000) self.assert_less_than_equal(hub.timers_canceled, 1000)
@skip_with_pyevent @skip_with_pyevent
def test_cancel_accumulated(self): def test_cancel_accumulated(self):
hub = hubs.get_hub() hub = hubs.get_hub()
@@ -81,6 +85,7 @@ class TestTimerCleanup(LimitedTestCase):
class TestScheduleCall(LimitedTestCase): class TestScheduleCall(LimitedTestCase):
def test_local(self): def test_local(self):
lst = [1] lst = [1]
eventlet.spawn(hubs.get_hub().schedule_call_local, DELAY, lst.pop) eventlet.spawn(hubs.get_hub().schedule_call_local, DELAY, lst.pop)
@@ -106,6 +111,7 @@ class TestScheduleCall(LimitedTestCase):
class TestDebug(LimitedTestCase): class TestDebug(LimitedTestCase):
def test_debug_listeners(self): def test_debug_listeners(self):
hubs.get_hub().set_debug_listeners(True) hubs.get_hub().set_debug_listeners(True)
hubs.get_hub().set_debug_listeners(False) hubs.get_hub().set_debug_listeners(False)
@@ -116,13 +122,17 @@ class TestDebug(LimitedTestCase):
class TestExceptionInMainloop(LimitedTestCase): class TestExceptionInMainloop(LimitedTestCase):
def test_sleep(self): def test_sleep(self):
# even if there was an error in the mainloop, the hub should continue to work # even if there was an error in the mainloop, the hub should continue
# to work
start = time.time() start = time.time()
eventlet.sleep(DELAY) eventlet.sleep(DELAY)
delay = time.time() - start delay = time.time() - start
assert delay >= DELAY*0.9, 'sleep returned after %s seconds (was scheduled for %s)' % (delay, DELAY) assert delay >= DELAY * \
0.9, 'sleep returned after %s seconds (was scheduled for %s)' % (
delay, DELAY)
def fail(): def fail():
1 // 0 1 // 0
@@ -133,10 +143,13 @@ class TestExceptionInMainloop(LimitedTestCase):
eventlet.sleep(DELAY) eventlet.sleep(DELAY)
delay = time.time() - start delay = time.time() - start
assert delay >= DELAY*0.9, 'sleep returned after %s seconds (was scheduled for %s)' % (delay, DELAY) assert delay >= DELAY * \
0.9, 'sleep returned after %s seconds (was scheduled for %s)' % (
delay, DELAY)
class TestExceptionInGreenthread(LimitedTestCase): class TestExceptionInGreenthread(LimitedTestCase):
@skip_unless(greenlets.preserves_excinfo) @skip_unless(greenlets.preserves_excinfo)
def test_exceptionpreservation(self): def test_exceptionpreservation(self):
# events for controlling execution order # events for controlling execution order
@@ -193,6 +206,7 @@ class TestExceptionInGreenthread(LimitedTestCase):
class TestHubSelection(LimitedTestCase): class TestHubSelection(LimitedTestCase):
def test_explicit_hub(self): def test_explicit_hub(self):
if getattr(hubs.get_hub(), 'uses_twisted_reactor', None): if getattr(hubs.get_hub(), 'uses_twisted_reactor', None):
# doesn't work with twisted # doesn't work with twisted
@@ -207,6 +221,7 @@ class TestHubSelection(LimitedTestCase):
class TestHubBlockingDetector(LimitedTestCase): class TestHubBlockingDetector(LimitedTestCase):
TEST_TIMEOUT = 10 TEST_TIMEOUT = 10
@skip_with_pyevent @skip_with_pyevent
def test_block_detect(self): def test_block_detect(self):
def look_im_blocking(): def look_im_blocking():
@@ -234,6 +249,7 @@ class TestHubBlockingDetector(LimitedTestCase):
class TestSuspend(LimitedTestCase): class TestSuspend(LimitedTestCase):
TEST_TIMEOUT = 3 TEST_TIMEOUT = 3
def test_suspend_doesnt_crash(self): def test_suspend_doesnt_crash(self):
import errno import errno
import os import os
@@ -269,6 +285,7 @@ except eventlet.Timeout:
class TestBadFilenos(LimitedTestCase): class TestBadFilenos(LimitedTestCase):
@skip_with_pyevent @skip_with_pyevent
def test_repeated_selects(self): def test_repeated_selects(self):
from eventlet.green import select from eventlet.green import select
@@ -276,8 +293,8 @@ class TestBadFilenos(LimitedTestCase):
self.assertRaises(ValueError, select.select, [-1], [], []) self.assertRaises(ValueError, select.select, [-1], [], [])
from tests.patcher_test import ProcessBase
class TestFork(ProcessBase): class TestFork(ProcessBase):
@skip_with_pyevent @skip_with_pyevent
def test_fork(self): def test_fork(self):
new_mod = """ new_mod = """
@@ -370,6 +387,41 @@ class TestDeadRunLoop(LimitedTestCase):
class Foo(object): class Foo(object):
pass pass
class TestDefaultHub(ProcessBase):
def test_kqueue_unsupported(self):
# https://github.com/eventlet/eventlet/issues/38
# get_hub on windows broken by kqueue
module_source = r'''
# Simulate absence of kqueue even on platforms that support it.
import select
try:
del select.kqueue
except AttributeError:
pass
import __builtin__
original_import = __builtin__.__import__
def fail_import(name, *args, **kwargs):
if 'epoll' in name:
raise ImportError('disabled for test')
if 'kqueue' in name:
print('kqueue tried')
return original_import(name, *args, **kwargs)
__builtin__.__import__ = fail_import
import eventlet.hubs
eventlet.hubs.get_default_hub()
print('ok')
'''
self.write_to_tempfile('newmod', module_source)
output, _ = self.launch_subprocess('newmod.py')
self.assertEqual(output, 'kqueue tried\nok\n')
if __name__ == '__main__': if __name__ == '__main__':
main() main()