diff --git a/doc/basic_usage.rst b/doc/basic_usage.rst index fa75ca6..4706dda 100644 --- a/doc/basic_usage.rst +++ b/doc/basic_usage.rst @@ -99,4 +99,91 @@ Though Eventlet has many modules, much of the most-used stuff is accessible simp Queues are a fundamental construct for communicating data between execution units. Eventlet's Queue class is used to communicate between greenthreads, and provides a bunch of useful features for doing that. See :class:`queue.Queue` for more details. +.. class:: eventlet.Timeout + Raises *exception* in the current greenthread after *timeout* seconds:: + + timeout = Timeout(seconds, exception) + try: + ... # execution here is limited by timeout + finally: + timeout.cancel() + + When *exception* is omitted or ``None``, the :class:`Timeout` instance + itself is raised: + + >>> Timeout(0.1) + >>> eventlet.sleep(0.2) + Traceback (most recent call last): + ... + Timeout: 0.1 seconds + + In Python 2.5 and newer, you can use the ``with`` statement for additional + convenience:: + + with Timeout(seconds, exception) as timeout: + pass # ... code block ... + + This is equivalent to the try/finally block in the first example. + + There is an additional feature when using the ``with`` statement: if + *exception* is ``False``, the timeout is still raised, but the with + statement suppresses it, so the code outside the with-block won't see it:: + + data = None + with Timeout(5, False): + data = mysock.makefile().readline() + if data is None: + ... # 5 seconds passed without reading a line + else: + ... # a line was read within 5 seconds + + As a very special case, if *seconds* is None, the timer is not scheduled, + and is only useful if you're planning to raise it directly. + + There are two Timeout caveats to be aware of: + + * If the code block in the try/finally or with-block never cooperatively yields, the timeout cannot be raised. In Eventlet, this should rarely be a problem, but be aware that you cannot time out CPU-only operations with this class. + * If the code block catches and doesn't re-raise :class:`BaseException` (for example, with ``except:``), then it will catch the Timeout exception, and might not abort as intended. + + When catching timeouts, keep in mind that the one you catch may not be the + one you have set; if you going to silence a timeout, always check that it's + the same instance that you set:: + + timeout = Timeout(1) + try: + ... + except Timeout, t: + if t is not timeout: + raise # not my timeout + + +.. function:: eventlet.with_timeout(seconds, function, *args, **kwds) + + Wrap a call to some (yielding) function with a timeout; if the called + function fails to return before the timeout, cancel it and return a flag + value. + + :param seconds: seconds before timeout occurs + :type seconds: int or float + :param func: the callable to execute with a timeout; it must cooperatively yield, or else the timeout will not be able to trigger + :param \*args: positional arguments to pass to *func* + :param \*\*kwds: keyword arguments to pass to *func* + :param timeout_value: value to return if timeout occurs (by default raises + :class:`Timeout`) + + :rtype: Value returned by *func* if *func* returns before *seconds*, else + *timeout_value* if provided, else raises :class:`Timeout`. + + :exception Timeout: if *func* times out and no ``timeout_value`` has + been provided. + :exception: Any exception raised by *func* + + Example:: + + data = with_timeout(30, urllib2.open, 'http://www.google.com/', timeout_value="") + + Here *data* is either the result of the ``get()`` call, or the empty string + if it took too long to return. Any exception raised by the ``get()`` call + is passed through to the caller. + These are the basic primitives of Eventlet; there are a lot more out there in the other Eventlet modules; check out the :doc:`modules`. diff --git a/eventlet/__init__.py b/eventlet/__init__.py index f56a53e..47dc0a1 100644 --- a/eventlet/__init__.py +++ b/eventlet/__init__.py @@ -5,21 +5,25 @@ try: from eventlet import greenthread from eventlet import greenpool from eventlet import queue + from eventlet import timeout sleep = greenthread.sleep - spawn = greenthread.spawn spawn_n = greenthread.spawn_n spawn_after = greenthread.spawn_after - call_after_global = greenthread.call_after_global - TimeoutError = greenthread.TimeoutError - exc_after = greenthread.exc_after - with_timeout = greenthread.with_timeout + + Timeout = timeout.Timeout + with_timeout = timeout.with_timeout GreenPool = greenpool.GreenPool GreenPile = greenpool.GreenPile Queue = queue.Queue + + # deprecated + TimeoutError = timeout.Timeout + exc_after = greenthread.exc_after + call_after_global = greenthread.call_after_global except ImportError: # this is to make Debian packaging easier import traceback diff --git a/eventlet/db_pool.py b/eventlet/db_pool.py index f9f117b..671d6a5 100644 --- a/eventlet/db_pool.py +++ b/eventlet/db_pool.py @@ -4,7 +4,8 @@ import time from eventlet.pools import Pool from eventlet.processes import DeadProcess -from eventlet import api +from eventlet import timeout +from eventlet import greenthread class ConnectTimeout(Exception): @@ -89,7 +90,7 @@ class BaseConnectionPool(Pool): if next_delay > 0: # set up a continuous self-calling loop - self._expiration_timer = api.call_after(next_delay, + self._expiration_timer = greenthread.spawn_after(next_delay, self._schedule_expiration) def _expire_old_connections(self, now): @@ -248,7 +249,7 @@ class TpooledConnectionPool(BaseConnectionPool): @classmethod def connect(cls, db_module, connect_timeout, *args, **kw): - timeout = api.exc_after(connect_timeout, ConnectTimeout()) + timeout = timeout.Timeout(connect_timeout, ConnectTimeout()) try: from eventlet import tpool conn = tpool.execute(db_module.connect, *args, **kw) @@ -268,7 +269,7 @@ class RawConnectionPool(BaseConnectionPool): @classmethod def connect(cls, db_module, connect_timeout, *args, **kw): - timeout = api.exc_after(connect_timeout, ConnectTimeout()) + timeout = timeout.Timeout(connect_timeout, ConnectTimeout()) try: return db_module.connect(*args, **kw) finally: diff --git a/eventlet/green/threading.py b/eventlet/green/threading.py index e729779..faf918b 100644 --- a/eventlet/green/threading.py +++ b/eventlet/green/threading.py @@ -2,7 +2,7 @@ from eventlet import patcher from eventlet.green import thread from eventlet.green import time -__patched__ = ['_start_new_thread', '_allocate_lock', '_get_ident'] +__patched__ = ['_start_new_thread', '_allocate_lock', '_get_ident', '_sleep'] patcher.inject('threading', globals(), diff --git a/eventlet/greenthread.py b/eventlet/greenthread.py index 043f436..221fe30 100644 --- a/eventlet/greenthread.py +++ b/eventlet/greenthread.py @@ -2,6 +2,7 @@ import sys from eventlet import event from eventlet import hubs +from eventlet import timeout from eventlet.hubs import timer from eventlet.support import greenlets as greenlet import warnings @@ -9,7 +10,6 @@ import warnings __all__ = ['getcurrent', 'sleep', 'spawn', 'spawn_n', 'call_after_global', 'call_after_local', 'GreenThread'] getcurrent = greenlet.getcurrent -TimeoutError = hubs.TimeoutError def sleep(seconds=0): """Yield control to another eligible coroutine until at least *seconds* have @@ -170,57 +170,17 @@ def exc_after(seconds, *throw_args): else: timer.cancel() """ + warnings.warn("Instead of exc_after, which is deprecated, use " + "Timeout(seconds, exception)", + DeprecationWarning, stacklevel=2) if seconds is None: # dummy argument, do nothing return timer.Timer(seconds, lambda: None) hub = hubs.get_hub() return hub.schedule_call_local(seconds, getcurrent().throw, *throw_args) - -def with_timeout(seconds, func, *args, **kwds): - """Wrap a call to some (yielding) function with a timeout; if the called - function fails to return before the timeout, cancel it and return a flag - value. - - :param seconds: seconds before timeout occurs - :type seconds: int or float - :param func: the callable to execute with a timeout; must be one of the - functions that implicitly or explicitly yields - :param \*args: positional arguments to pass to *func* - :param \*\*kwds: keyword arguments to pass to *func* - :param timeout_value: value to return if timeout occurs (default raise - :class:`~eventlet.api.TimeoutError`) - - :rtype: Value returned by *func* if *func* returns before *seconds*, else - *timeout_value* if provided, else raise ``TimeoutError`` - - :exception TimeoutError: if *func* times out and no ``timeout_value`` has - been provided. - :exception *any*: Any exception raised by *func* - - **Example**:: - - data = with_timeout(30, httpc.get, 'http://www.google.com/', timeout_value="") - - Here *data* is either the result of the ``get()`` call, or the empty string if - it took too long to return. Any exception raised by the ``get()`` call is - passed through to the caller. - """ - # Recognize a specific keyword argument, while also allowing pass-through - # of any other keyword arguments accepted by func. Use pop() so we don't - # pass timeout_value through to func(). - has_timeout_value = "timeout_value" in kwds - timeout_value = kwds.pop("timeout_value", None) - error = TimeoutError() - timeout = exc_after(seconds, error) - try: - try: - return func(*args, **kwds) - except TimeoutError, ex: - if ex is error and has_timeout_value: - return timeout_value - raise - finally: - timeout.cancel() +# deprecate, remove +TimeoutError = timeout.Timeout +with_timeout = timeout.with_timeout def _spawn_n(seconds, func, args, kwargs): hub = hubs.get_hub() diff --git a/eventlet/hubs/__init__.py b/eventlet/hubs/__init__.py index cf1aec8..aa6d56d 100644 --- a/eventlet/hubs/__init__.py +++ b/eventlet/hubs/__init__.py @@ -83,12 +83,9 @@ def get_hub(): hub = _threadlocal.hub = _threadlocal.Hub() return hub -class TimeoutError(Exception): - """Exception raised if an asynchronous operation times out""" - pass - +from eventlet import timeout def trampoline(fd, read=None, write=None, timeout=None, - timeout_exc=TimeoutError): + timeout_exc=timeout.Timeout): """Suspend the current coroutine until the given socket object or file descriptor is ready to *read*, ready to *write*, or the specified *timeout* elapses, depending on arguments specified. diff --git a/eventlet/hubs/pyevent.py b/eventlet/hubs/pyevent.py index 6f6234e..a067ae5 100644 --- a/eventlet/hubs/pyevent.py +++ b/eventlet/hubs/pyevent.py @@ -29,7 +29,10 @@ class event_wrapper(object): if self.impl is not None: self.impl.delete() self.impl = None - + + @property + def pending(self): + return bool(self.impl and self.impl.pending()) class Hub(BaseHub): diff --git a/eventlet/hubs/timer.py b/eventlet/hubs/timer.py index f4f46d0..e4c185e 100644 --- a/eventlet/hubs/timer.py +++ b/eventlet/hubs/timer.py @@ -29,6 +29,10 @@ class Timer(object): @property def cancelled(self): return self._cancelled + + @property + def pending(self): + return not (self._cancelled or self.called) def __repr__(self): secs = getattr(self, 'seconds', None) diff --git a/eventlet/queue.py b/eventlet/queue.py index e63a6ac..342f4e3 100644 --- a/eventlet/queue.py +++ b/eventlet/queue.py @@ -28,8 +28,9 @@ from Queue import Full, Empty _NONE = object() from eventlet.hubs import get_hub -from eventlet.greenthread import getcurrent, exc_after +from eventlet.greenthread import getcurrent from eventlet.event import Event +from eventlet.timeout import Timeout __all__ = ['Queue', 'PriorityQueue', 'LifoQueue', 'LightQueue', 'Full', 'Empty'] @@ -211,7 +212,7 @@ class LightQueue(object): elif block: waiter = ItemWaiter(item) self.putters.add(waiter) - timeout = exc_after(timeout, Full) + timeout = Timeout(timeout, Full) try: if self.getters: self._schedule_unlock() @@ -259,7 +260,7 @@ class LightQueue(object): raise Empty elif block: waiter = Waiter() - timeout = exc_after(timeout, Empty) + timeout = Timeout(timeout, Empty) try: self.getters.add(waiter) if self.putters: diff --git a/eventlet/timeout.py b/eventlet/timeout.py new file mode 100644 index 0000000..d063ab7 --- /dev/null +++ b/eventlet/timeout.py @@ -0,0 +1,128 @@ +# Copyright (c) 2009-2010 Denis Bilenko and Eventlet contributors. See LICENSE for details. +from eventlet.support import greenlets as greenlet +from eventlet.hubs import get_hub + +__all__ = ['Timeout', + 'with_timeout'] + +_NONE = object() + +try: + BaseException +except NameError: # Python < 2.5 + class BaseException: + # not subclassing from object() intentionally, because in + # that case "raise Timeout" fails with TypeError. + pass + +# deriving from BaseException so that "except Exception, e" doesn't catch +# Timeout exceptions. +class Timeout(BaseException): + """Raises *exception* in the current greenthread after *timeout* seconds. + + When *exception* is omitted or ``None``, the :class:`Timeout` instance + itself is raised. If *seconds* is None, the timer is not scheduled, and is + only useful if you're planning to raise it directly. + + Timeout objects are context managers, and so can be used in with statements. + When used in a with statement, if *exception* is ``False``, the timeout is + still raised, but the context manager suppresses it, so the code outside the + with-block won't see it. + """ + + def __init__(self, seconds=None, exception=None): + self.seconds = seconds + self.exception = exception + self.timer = None + self.start() + + def start(self): + """Schedule the timeout. This is called on construction, so + it should not be called explicitly, unless the timer has been + cancelled.""" + assert not self.pending, '%r is already started; to restart it, cancel it first' % self + if self.seconds is None: # "fake" timeout (never expires) + self.timer = None + elif self.exception is None or self.exception is False: # timeout that raises self + self.timer = get_hub().schedule_call_global(self.seconds, greenlet.getcurrent().throw, self) + else: # regular timeout with user-provided exception + self.timer = get_hub().schedule_call_global(self.seconds, greenlet.getcurrent().throw, self.exception) + return self + + @property + def pending(self): + """Return True if the timeout is scheduled to be raised.""" + if self.timer is not None: + return self.timer.pending + else: + return False + + def cancel(self): + """If the timeout is pending, cancel it. Otherwise, do nothing.""" + if self.timer is not None: + self.timer.cancel() + self.timer = None + + def __repr__(self): + try: + classname = self.__class__.__name__ + except AttributeError: # Python < 2.5 + classname = 'Timeout' + if self.pending: + pending = ' pending' + else: + pending = '' + if self.exception is None: + exception = '' + else: + exception = ' exception=%r' % self.exception + return '<%s at %s seconds=%s%s%s>' % (classname, hex(id(self)), self.seconds, exception, pending) + + def __str__(self): + """ + >>> raise Timeout + Traceback (most recent call last): + ... + Timeout + """ + if self.seconds is None: + return '' + if self.seconds == 1: + suffix = '' + else: + suffix = 's' + if self.exception is None: + return '%s second%s' % (self.seconds, suffix) + elif self.exception is False: + return '%s second%s (silent)' % (self.seconds, suffix) + else: + return '%s second%s (%s)' % (self.seconds, suffix, self.exception) + + def __enter__(self): + if self.timer is None: + self.start() + return self + + def __exit__(self, typ, value, tb): + self.cancel() + if value is self and self.exception is False: + return True + + +def with_timeout(seconds, function, *args, **kwds): + """Wrap a call to some (yielding) function with a timeout; if the called + function fails to return before the timeout, cancel it and return a flag + value. + """ + timeout_value = kwds.pop("timeout_value", _NONE) + timeout = Timeout(seconds) + try: + try: + return function(*args, **kwds) + except Timeout, ex: + if ex is timeout and timeout_value is not _NONE: + return timeout_value + raise + finally: + timeout.cancel() + diff --git a/tests/__init__.py b/tests/__init__.py index 5102c34..e8a6a91 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -99,9 +99,9 @@ class LimitedTestCase(unittest.TestCase): TEST_TIMEOUT = 1 def setUp(self): - from eventlet import api - self.timer = api.exc_after(self.TEST_TIMEOUT, - TestIsTakingTooLong(self.TEST_TIMEOUT)) + import eventlet + self.timer = eventlet.Timeout(self.TEST_TIMEOUT, + TestIsTakingTooLong(self.TEST_TIMEOUT)) def tearDown(self): self.timer.cancel() diff --git a/tests/db_pool_test.py b/tests/db_pool_test.py index c19ed43..e1ec284 100644 --- a/tests/db_pool_test.py +++ b/tests/db_pool_test.py @@ -2,9 +2,9 @@ from tests import skipped, skip_unless, skip_with_pyevent from unittest import TestCase, main -from eventlet import api from eventlet import event from eventlet import db_pool +import eventlet import os class DBTester(object): @@ -145,7 +145,7 @@ class DBConnectionPool(DBTester): results.append(2) evt.send() evt2 = event.Event() - api.spawn(a_query) + eventlet.spawn(a_query) results.append(1) self.assertEqual([1], results) evt.wait() @@ -232,8 +232,8 @@ class DBConnectionPool(DBTester): results.append(2) evt2.send() - api.spawn(long_running_query) - api.spawn(short_running_query) + eventlet.spawn(long_running_query) + eventlet.spawn(short_running_query) evt.wait() evt2.wait() results.sort() @@ -304,17 +304,17 @@ class DBConnectionPool(DBTester): self.connection = self.pool.get() self.connection.close() self.assertEquals(len(self.pool.free_items), 1) - api.sleep(0.01) # not long enough to trigger the idle timeout + eventlet.sleep(0.01) # not long enough to trigger the idle timeout self.assertEquals(len(self.pool.free_items), 1) self.connection = self.pool.get() self.connection.close() self.assertEquals(len(self.pool.free_items), 1) - api.sleep(0.01) # idle timeout should have fired but done nothing + eventlet.sleep(0.01) # idle timeout should have fired but done nothing self.assertEquals(len(self.pool.free_items), 1) self.connection = self.pool.get() self.connection.close() self.assertEquals(len(self.pool.free_items), 1) - api.sleep(0.03) # long enough to trigger idle timeout for real + eventlet.sleep(0.03) # long enough to trigger idle timeout for real self.assertEquals(len(self.pool.free_items), 0) @skipped @@ -323,11 +323,11 @@ class DBConnectionPool(DBTester): self.pool = self.create_pool(max_size=2, max_idle=0.02) self.connection, conn2 = self.pool.get(), self.pool.get() self.connection.close() - api.sleep(0.01) + eventlet.sleep(0.01) self.assertEquals(len(self.pool.free_items), 1) conn2.close() self.assertEquals(len(self.pool.free_items), 2) - api.sleep(0.02) # trigger cleanup of conn1 but not conn2 + eventlet.sleep(0.02) # trigger cleanup of conn1 but not conn2 self.assertEquals(len(self.pool.free_items), 1) @skipped @@ -337,12 +337,12 @@ class DBConnectionPool(DBTester): self.connection = self.pool.get() self.connection.close() self.assertEquals(len(self.pool.free_items), 1) - api.sleep(0.01) # not long enough to trigger the age timeout + eventlet.sleep(0.01) # not long enough to trigger the age timeout self.assertEquals(len(self.pool.free_items), 1) self.connection = self.pool.get() self.connection.close() self.assertEquals(len(self.pool.free_items), 1) - api.sleep(0.05) # long enough to trigger age timeout + eventlet.sleep(0.05) # long enough to trigger age timeout self.assertEquals(len(self.pool.free_items), 0) @skipped @@ -352,9 +352,9 @@ class DBConnectionPool(DBTester): self.connection, conn2 = self.pool.get(), self.pool.get() self.connection.close() self.assertEquals(len(self.pool.free_items), 1) - api.sleep(0) # not long enough to trigger the age timeout + eventlet.sleep(0) # not long enough to trigger the age timeout self.assertEquals(len(self.pool.free_items), 1) - api.sleep(0.2) # long enough to trigger age timeout + eventlet.sleep(0.2) # long enough to trigger age timeout self.assertEquals(len(self.pool.free_items), 0) conn2.close() # should not be added to the free items self.assertEquals(len(self.pool.free_items), 0) @@ -374,13 +374,13 @@ class DBConnectionPool(DBTester): def retrieve(pool, ev): c = pool.get() ev.send(c) - api.spawn(retrieve, self.pool, e) - api.sleep(0) # these two sleeps should advance the retrieve - api.sleep(0) # coroutine until it's waiting in get() + eventlet.spawn(retrieve, self.pool, e) + eventlet.sleep(0) # these two sleeps should advance the retrieve + eventlet.sleep(0) # coroutine until it's waiting in get() self.assertEquals(self.pool.free(), 0) self.assertEquals(self.pool.waiting(), 1) self.pool.put(self.connection) - timer = api.exc_after(1, api.TimeoutError) + timer = eventlet.Timeout(1) conn = e.wait() timer.cancel() self.assertEquals(self.pool.free(), 0) diff --git a/tests/event_test.py b/tests/event_test.py index f2e81aa..caf2672 100644 --- a/tests/event_test.py +++ b/tests/event_test.py @@ -64,6 +64,6 @@ class TestEvent(LimitedTestCase): self.assertRaises(RuntimeError, evt.wait) evt.reset() # shouldn't see the RuntimeError again - eventlet.exc_after(0.001, eventlet.TimeoutError('from test_double_exception')) - self.assertRaises(eventlet.TimeoutError, evt.wait) + eventlet.Timeout(0.001) + self.assertRaises(eventlet.Timeout, evt.wait) diff --git a/tests/greenio_test.py b/tests/greenio_test.py index 167885e..f956954 100644 --- a/tests/greenio_test.py +++ b/tests/greenio_test.py @@ -246,7 +246,7 @@ class TestGreenIo(LimitedTestCase): try: # try and get some data off of this pipe # but bail before any is sent - eventlet.exc_after(0.01, eventlet.TimeoutError) + eventlet.Timeout(0.01) client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect(('127.0.0.1', bound_port)) wrap_rfile = client.makefile() diff --git a/tests/greenpool_test.py b/tests/greenpool_test.py index c492ebe..f668188 100644 --- a/tests/greenpool_test.py +++ b/tests/greenpool_test.py @@ -120,7 +120,7 @@ class GreenPool(tests.LimitedTestCase): self.assertEquals(pool.free(), num_free) def wait_long_time(e): e.wait() - timer = eventlet.exc_after(1, eventlet.TimeoutError) + timer = eventlet.Timeout(1) try: evt = event.Event() for x in xrange(num_free): @@ -132,7 +132,7 @@ class GreenPool(tests.LimitedTestCase): # if the runtime error is not raised it means the pool had # some unexpected free items - timer = eventlet.exc_after(0, RuntimeError()) + timer = eventlet.Timeout(0, RuntimeError) try: self.assertRaises(RuntimeError, pool.spawn, wait_long_time, evt) finally: @@ -182,7 +182,7 @@ class GreenPool(tests.LimitedTestCase): tp = pools.TokenPool(max_size=1) token = tp.get() # empty out the pool def do_receive(tp): - timer = eventlet.exc_after(0, RuntimeError()) + timer = eventlet.Timeout(0, RuntimeError()) try: t = tp.get() self.fail("Shouldn't have recieved anything from the pool") @@ -316,8 +316,8 @@ class GreenPile(tests.LimitedTestCase): for i in xrange(4): p.spawn(passthru, i) # now it should be full and this should time out - eventlet.exc_after(0, eventlet.TimeoutError) - self.assertRaises(eventlet.TimeoutError, p.spawn, passthru, "time out") + eventlet.Timeout(0) + self.assertRaises(eventlet.Timeout, p.spawn, passthru, "time out") # verify that the spawn breakage didn't interrupt the sequence # and terminates properly for i in xrange(4,10): diff --git a/tests/nosewrapper.py b/tests/nosewrapper.py index 584f4f4..43c4366 100644 --- a/tests/nosewrapper.py +++ b/tests/nosewrapper.py @@ -10,7 +10,7 @@ if parent_dir not in sys.path: # hacky hacks: skip test__api_timeout when under 2.4 because otherwise it SyntaxErrors if sys.version_info < (2,5): - argv = sys.argv + ["--exclude=.*test__api_timeout.*"] + argv = sys.argv + ["--exclude=.*timeout_test_with_statement.*"] else: argv = sys.argv diff --git a/tests/pools_test.py b/tests/pools_test.py index c4d07ed..61a1f70 100644 --- a/tests/pools_test.py +++ b/tests/pools_test.py @@ -1,5 +1,6 @@ from unittest import TestCase, main +import eventlet from eventlet import api from eventlet import coros from eventlet import pools @@ -11,7 +12,6 @@ class IntPool(pools.Pool): class TestIntPool(TestCase): - mode = 'static' def setUp(self): self.pool = IntPool(min_size=0, max_size=4) @@ -103,7 +103,7 @@ class TestIntPool(TestCase): self.assertEquals(self.pool.get(), two) def test_putting_to_queue(self): - timer = api.exc_after(0.1, api.TimeoutError) + timer = eventlet.Timeout(0.1) try: size = 2 self.pool = IntPool(min_size=0, max_size=size) diff --git a/tests/queue_test.py b/tests/queue_test.py index fd6466b..99a713b 100644 --- a/tests/queue_test.py +++ b/tests/queue_test.py @@ -3,7 +3,7 @@ import eventlet from eventlet import event def do_bail(q): - eventlet.exc_after(0, RuntimeError()) + eventlet.Timeout(0, RuntimeError()) try: result = q.get() return result diff --git a/tests/stdlib/all.py b/tests/stdlib/all.py index 65f20c8..ca46ff0 100644 --- a/tests/stdlib/all.py +++ b/tests/stdlib/all.py @@ -27,7 +27,7 @@ def assimilate_patched(name): test_method() restart_hub() globals()[method_name] = test_main - modobj.test_main.__name__ = name + '.test_main' + test_main.__name__ = name + '.test_main' except AttributeError: print "No test_main for %s, assuming it tests on import" % name diff --git a/tests/test__api_timeout.py b/tests/test__api_timeout.py deleted file mode 100644 index 49c3ed2..0000000 --- a/tests/test__api_timeout.py +++ /dev/null @@ -1,106 +0,0 @@ -from __future__ import with_statement -import sys -import unittest -import weakref -import time -from eventlet.api import sleep, timeout, TimeoutError, _SilentException -DELAY = 0.01 - -class Error(Exception): - pass - -class Test(unittest.TestCase): - - def test_api(self): - # Nothing happens if with-block finishes before the timeout expires - with timeout(DELAY*2): - sleep(DELAY) - sleep(DELAY*2) # check if timer was actually cancelled - - # An exception will be raised if it's not - try: - with timeout(DELAY): - sleep(DELAY*2) - except TimeoutError: - pass - else: - raise AssertionError('must raise TimeoutError') - - # You can customize the exception raised: - try: - with timeout(DELAY, IOError("Operation takes way too long")): - sleep(DELAY*2) - except IOError, ex: - assert str(ex)=="Operation takes way too long", repr(ex) - - # Providing classes instead of values should be possible too: - try: - with timeout(DELAY, ValueError): - sleep(DELAY*2) - except ValueError: - pass - - # basically, anything that greenlet.throw accepts work: - try: - 1/0 - except: - try: - with timeout(DELAY, *sys.exc_info()): - sleep(DELAY*2) - raise AssertionError('should not get there') - raise AssertionError('should not get there') - except ZeroDivisionError: - pass - else: - raise AssertionError('should not get there') - - # It's possible to cancel the timer inside the block: - with timeout(DELAY) as timer: - timer.cancel() - sleep(DELAY*2) - - # To silent the exception, pass None as second parameter. The with-block - # will be interrupted with _SilentException, but it won't be propagated - # outside. - XDELAY=0.1 - start = time.time() - with timeout(XDELAY, None): - sleep(XDELAY*10) - delta = (time.time()-start) - assert delta