From a8f22fc89532a523e4a7bed2df6759e9544fe149 Mon Sep 17 00:00:00 2001 From: Ryan Williams Date: Mon, 4 Jan 2010 21:46:53 -0800 Subject: [PATCH] Moved a bunch of stuff from api to greenthread and imported into __init__. Broke circular import in timer.py. --- eventlet/__init__.py | 7 +++- eventlet/api.py | 82 ++--------------------------------------- eventlet/greenthread.py | 82 +++++++++++++++++++++++++++++++++++++++++ eventlet/timer.py | 4 +- 4 files changed, 94 insertions(+), 81 deletions(-) diff --git a/eventlet/__init__.py b/eventlet/__init__.py index fecbe28..1f13d59 100644 --- a/eventlet/__init__.py +++ b/eventlet/__init__.py @@ -11,6 +11,11 @@ sleep = greenthread.sleep spawn = greenthread.spawn spawn_n = greenthread.spawn_n Event = greenthread.Event +call_after_global = greenthread.call_after_global +call_after_local = greenthread.call_after_local +TimeoutError = greenthread.TimeoutError +exc_after = greenthread.exc_after +with_timeout = greenthread.with_timeout GreenPool = greenpool.GreenPool -GreenPile = greenpool.GreenPile \ No newline at end of file +GreenPile = greenpool.GreenPile diff --git a/eventlet/api.py b/eventlet/api.py index 8ba15bf..75df040 100644 --- a/eventlet/api.py +++ b/eventlet/api.py @@ -8,6 +8,7 @@ import warnings from eventlet.support import greenlets as greenlet from eventlet.hubs import get_hub as get_hub_, get_default_hub as get_default_hub_, use_hub as use_hub_ +from eventlet import greenthread __all__ = [ 'call_after', 'exc_after', 'getcurrent', 'get_default_hub', 'get_hub', @@ -37,10 +38,6 @@ def switch(coro, result=None, exc=None): Greenlet = greenlet.greenlet -class TimeoutError(Exception): - """Exception raised if an asynchronous operation times out""" - pass - def tcp_listener(address, backlog=50): """ @@ -80,6 +77,7 @@ def connect_tcp(address, localaddr=None): desc.connect(address) return desc +TimeoutError = greenthread.TimeoutError def trampoline(fd, read=None, write=None, timeout=None, timeout_exc=TimeoutError): """Suspend the current coroutine until the given socket object or file @@ -118,7 +116,6 @@ def trampoline(fd, read=None, write=None, timeout=None, timeout_exc=TimeoutError t.cancel() -from eventlet import greenthread spawn = greenthread.spawn spawn_n = greenthread.spawn_n @@ -186,80 +183,9 @@ class timeout(object): if typ is _SilentException and value in self.throw_args: return True -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. +with_timeout = greenthread.with_timeout - :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() - - -def exc_after(seconds, *throw_args): - """Schedule an exception to be raised into the current coroutine - after *seconds* have elapsed. - - This only works if the current coroutine is yielding, and is generally - used to set timeouts after which a network operation or series of - operations will be canceled. - - Returns a :class:`~eventlet.timer.Timer` object with a - :meth:`~eventlet.timer.Timer.cancel` method which should be used to - prevent the exception if the operation completes successfully. - - See also :func:`~eventlet.api.with_timeout` that encapsulates the idiom below. - - Example:: - - def read_with_timeout(): - timer = api.exc_after(30, RuntimeError()) - try: - httpc.get('http://www.google.com/') - except RuntimeError: - print "Timed out!" - else: - timer.cancel() - """ - return call_after(seconds, getcurrent().throw, *throw_args) - +exc_after = greenthread.exc_after sleep = greenthread.sleep diff --git a/eventlet/greenthread.py b/eventlet/greenthread.py index 708ea64..7c83a2a 100644 --- a/eventlet/greenthread.py +++ b/eventlet/greenthread.py @@ -1,6 +1,7 @@ import sys from eventlet import hubs +from eventlet import timer from eventlet.support import greenlets as greenlet __all__ = ['getcurrent', 'sleep', 'spawn', 'spawn_n', 'call_after_global', 'call_after_local', 'GreenThread', 'Event'] @@ -80,6 +81,87 @@ def call_after_local(seconds, function, *args, **kwargs): call_after = call_after_local +class TimeoutError(Exception): + """Exception raised if an asynchronous operation times out""" + pass + +def exc_after(seconds, *throw_args): + """Schedule an exception to be raised into the current coroutine + after *seconds* have elapsed. + + This only works if the current coroutine is yielding, and is generally + used to set timeouts after which a network operation or series of + operations will be canceled. + + Returns a :class:`~eventlet.timer.Timer` object with a + :meth:`~eventlet.timer.Timer.cancel` method which should be used to + prevent the exception if the operation completes successfully. + + See also :func:`~eventlet.api.with_timeout` that encapsulates the idiom below. + + Example:: + + def read_with_timeout(): + timer = api.exc_after(30, RuntimeError()) + try: + httpc.get('http://www.google.com/') + except RuntimeError: + print "Timed out!" + else: + timer.cancel() + """ + 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() + def _spawn_n(seconds, func, args, kwargs): hub = hubs.get_hub() diff --git a/eventlet/timer.py b/eventlet/timer.py index 2154e88..f4f46d0 100644 --- a/eventlet/timer.py +++ b/eventlet/timer.py @@ -1,4 +1,4 @@ -from eventlet.api import getcurrent +from eventlet.support import greenlets as greenlet from eventlet.hubs import get_hub """ If true, captures a stack trace for each timer when constructed. This is @@ -74,7 +74,7 @@ class Timer(object): class LocalTimer(Timer): def __init__(self, *args, **kwargs): - self.greenlet = getcurrent() + self.greenlet = greenlet.getcurrent() Timer.__init__(self, *args, **kwargs) @property