Added spawn_after_local and tests, removed test__timers (the source of the new tests), deprecated call_after_*

This commit is contained in:
Ryan Williams
2010-02-13 19:38:01 -08:00
parent 64ad004e5d
commit 7fb4f59ac8
5 changed files with 65 additions and 42 deletions

View File

@@ -10,6 +10,7 @@ try:
spawn = greenthread.spawn spawn = greenthread.spawn
spawn_n = greenthread.spawn_n spawn_n = greenthread.spawn_n
spawn_after = greenthread.spawn_after
call_after_global = greenthread.call_after_global call_after_global = greenthread.call_after_global
TimeoutError = greenthread.TimeoutError TimeoutError = greenthread.TimeoutError
exc_after = greenthread.exc_after exc_after = greenthread.exc_after

View File

@@ -4,6 +4,7 @@ from eventlet import event
from eventlet import hubs from eventlet import hubs
from eventlet.hubs import timer from eventlet.hubs import timer
from eventlet.support import greenlets as greenlet from eventlet.support import greenlets as greenlet
import warnings
__all__ = ['getcurrent', 'sleep', 'spawn', 'spawn_n', 'call_after_global', 'call_after_local', 'GreenThread'] __all__ = ['getcurrent', 'sleep', 'spawn', 'spawn_n', 'call_after_global', 'call_after_local', 'GreenThread']
@@ -81,7 +82,30 @@ def spawn_after(seconds, func, *args, **kwargs):
g = GreenThread(hub.greenlet) g = GreenThread(hub.greenlet)
hub.schedule_call_global(seconds, g.switch, func, args, kwargs) hub.schedule_call_global(seconds, g.switch, func, args, kwargs)
return g return g
def spawn_after_local(seconds, func, *args, **kwargs):
"""Spawns *func* after *seconds* have elapsed. The function will NOT be
called if the current greenthread has exited.
*seconds* may be specified as an integer, or a float if fractional seconds
are desired. The *func* will be called with the given *args* and
keyword arguments *kwargs*, and will be executed within its own greenthread.
The return value of :func:`spawn_after` is a :class:`GreenThread` object,
which can be used to retrieve the results of the call.
To cancel the spawn and prevent *func* from being called,
call :meth:`GreenThread.cancel` on the return value. This will not abort the
function if it's already started running. If terminating *func* regardless
of whether it's started or not is the desired behavior, call
:meth:`GreenThread.kill`.
"""
hub = hubs.get_hub()
g = GreenThread(hub.greenlet)
hub.schedule_call_local(seconds, g.switch, func, args, kwargs)
return g
def call_after_global(seconds, func, *args, **kwargs): def call_after_global(seconds, func, *args, **kwargs):
"""Schedule *function* to be called after *seconds* have elapsed. """Schedule *function* to be called after *seconds* have elapsed.
@@ -92,6 +116,10 @@ def call_after_global(seconds, func, *args, **kwargs):
keyword arguments *kwargs*, and will be executed within its own greenthread. keyword arguments *kwargs*, and will be executed within its own greenthread.
Its return value is discarded.""" Its return value is discarded."""
warnings.warn("call_after_global is renamed to spawn_after, which"
"has the same signature and semantics (plus a bit extra). Please do a"
" quick search-and-replace on your codebase, thanks!",
DeprecationWarning, stacklevel=2)
return _spawn_n(seconds, func, args, kwargs)[0] return _spawn_n(seconds, func, args, kwargs)[0]
@@ -105,6 +133,9 @@ def call_after_local(seconds, function, *args, **kwargs):
Its return value is discarded. Its return value is discarded.
""" """
warnings.warn("call_after_local is renamed to spawn_after_local, which"
"has the same signature and semantics (plus a bit extra).",
DeprecationWarning, stacklevel=2)
hub = hubs.get_hub() hub = hubs.get_hub()
g = greenlet.greenlet(_main_wrapper, parent=hub.greenlet) g = greenlet.greenlet(_main_wrapper, parent=hub.greenlet)
t = hub.schedule_call_local(seconds, g.switch, function, args, kwargs) t = hub.schedule_call_local(seconds, g.switch, function, args, kwargs)

View File

@@ -107,3 +107,35 @@ class SpawnAfter(LimitedTestCase, Asserts):
greenthread.sleep(0) greenthread.sleep(0)
gt.kill() gt.kill()
self.assert_dead(gt) self.assert_dead(gt)
class SpawnAfterLocal(LimitedTestCase, Asserts):
def setUp(self):
super(SpawnAfterLocal, self).setUp()
self.lst = [1]
def test_timer_fired(self):
def func():
greenthread.spawn_after_local(0.1, self.lst.pop)
greenthread.sleep(0.2)
greenthread.spawn(func)
assert self.lst == [1], self.lst
greenthread.sleep(0.3)
assert self.lst == [], self.lst
def test_timer_cancelled_upon_greenlet_exit(self):
def func():
greenthread.spawn_after_local(0.1, self.lst.pop)
greenthread.spawn(func)
assert self.lst == [1], self.lst
greenthread.sleep(0.2)
assert self.lst == [1], self.lst
def test_spawn_is_not_cancelled(self):
def func():
greenthread.spawn(self.lst.pop)
# exiting immediatelly, but self.lst.pop must be called
greenthread.spawn(func)
greenthread.sleep(0.1)
assert self.lst == [], self.lst

View File

@@ -1,42 +0,0 @@
import unittest
from eventlet.api import call_after, spawn, sleep
class test(unittest.TestCase):
def setUp(self):
self.lst = [1]
def test_timer_fired(self):
def func():
call_after(0.1, self.lst.pop)
sleep(0.2)
spawn(func)
assert self.lst == [1], self.lst
sleep(0.3)
assert self.lst == [], self.lst
def test_timer_cancelled_upon_greenlet_exit(self):
def func():
call_after(0.1, self.lst.pop)
spawn(func)
assert self.lst == [1], self.lst
sleep(0.2)
assert self.lst == [1], self.lst
def test_spawn_is_not_cancelled(self):
def func():
spawn(self.lst.pop)
# exiting immediatelly, but self.lst.pop must be called
spawn(func)
sleep(0.1)
assert self.lst == [], self.lst
if __name__=='__main__':
unittest.main()

View File

@@ -31,6 +31,7 @@ class TestTimer(TestCase):
hub.switch() hub.switch()
assert called assert called
assert not hub.running assert not hub.running
if __name__ == '__main__': if __name__ == '__main__':
main() main()