From bf3944b0e19185cc38ab76e14da4bb89868c82be Mon Sep 17 00:00:00 2001 From: Ryan Williams Date: Sat, 19 Jun 2010 18:42:30 -0700 Subject: [PATCH] Tweaked the implementation of Timeout so that passing True as the exception class is the same as passing None, because it seemed inconsistent that one boolean value would have special nice behavior and the other would cause weird exceptions. --- eventlet/timeout.py | 4 ++-- examples/producer_consumer.py | 6 +++--- tests/timeout_test_with_statement.py | 24 ++++++++++++++++++++++-- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/eventlet/timeout.py b/eventlet/timeout.py index 135545b..573f4ab 100644 --- a/eventlet/timeout.py +++ b/eventlet/timeout.py @@ -57,7 +57,7 @@ class Timeout(BaseException): '%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 + elif self.exception is None or isinstance(self.exception, bool): # timeout that raises self self.timer = get_hub().schedule_call_global( self.seconds, greenlet.getcurrent().throw, self) else: # regular timeout with user-provided exception @@ -112,7 +112,7 @@ class Timeout(BaseException): suffix = '' else: suffix = 's' - if self.exception is None: + if self.exception is None or self.exception is True: return '%s second%s' % (self.seconds, suffix) elif self.exception is False: return '%s second%s (silent)' % (self.seconds, suffix) diff --git a/examples/producer_consumer.py b/examples/producer_consumer.py index b335f7d..6f6c82f 100644 --- a/examples/producer_consumer.py +++ b/examples/producer_consumer.py @@ -2,7 +2,7 @@ it doesn't respect robots.txt and it is pretty brutal about how quickly it fetches pages. -This is a kind of "producer/consumer" example; the producer function produces +This is a kind of "producer/consumer" example; the fetch function produces jobs, and the GreenPool itself is the consumer, farming out work concurrently. It's easier to write it this way rather than writing a standard consumer loop; GreenPool handles any exceptions raised and arranges so that there's a set @@ -43,10 +43,10 @@ def producer(start_url): # limit requests to eventlet.net so we don't crash all over the internet if url not in seen and 'eventlet.net' in url: seen.add(url) - pool.spawn(fetch, url, q) + pool.spawn_n(fetch, url, q) return seen seen = producer("http://eventlet.net") print "I saw these urls:" -print "\n".join(seen) \ No newline at end of file +print "\n".join(seen) diff --git a/tests/timeout_test_with_statement.py b/tests/timeout_test_with_statement.py index 48fe0b5..21779ce 100644 --- a/tests/timeout_test_with_statement.py +++ b/tests/timeout_test_with_statement.py @@ -15,7 +15,7 @@ class Error(Exception): pass class Test(LimitedTestCase): - def test_api(self): + def test_cancellation(self): # Nothing happens if with-block finishes before the timeout expires t = Timeout(DELAY*2) sleep(0) # make it pending @@ -27,6 +27,7 @@ class Test(LimitedTestCase): assert not t.pending, repr(t) sleep(DELAY*2) + def test_raising_self(self): # An exception will be raised if it's not try: with Timeout(DELAY) as t: @@ -36,6 +37,17 @@ class Test(LimitedTestCase): else: raise AssertionError('must raise Timeout') + def test_raising_self_true(self): + # specifying True as the exception raises self as well + try: + with Timeout(DELAY, True) as t: + sleep(DELAY*2) + except Timeout, ex: + assert ex is t, (ex, t) + else: + raise AssertionError('must raise Timeout') + + def test_raising_custom_exception(self): # You can customize the exception raised: try: with Timeout(DELAY, IOError("Operation takes way too long")): @@ -43,6 +55,7 @@ class Test(LimitedTestCase): except IOError, ex: assert str(ex)=="Operation takes way too long", repr(ex) + def test_raising_exception_class(self): # Providing classes instead of values should be possible too: try: with Timeout(DELAY, ValueError): @@ -50,6 +63,7 @@ class Test(LimitedTestCase): except ValueError: pass + def test_raising_exc_tuple(self): try: 1//0 except: @@ -63,12 +77,16 @@ class Test(LimitedTestCase): else: raise AssertionError('should not get there') + def test_cancel_timer_inside_block(self): # It's possible to cancel the timer inside the block: with Timeout(DELAY) as timer: timer.cancel() sleep(DELAY*2) - # To silent the exception before exiting the block, pass False as second parameter. + + def test_silent_block(self): + # To silence the exception before exiting the block, pass + # False as second parameter. XDELAY=0.1 start = time.time() with Timeout(XDELAY, False): @@ -76,6 +94,8 @@ class Test(LimitedTestCase): delta = (time.time()-start) assert delta