crochet
crochet copied to clipboard
wait_for and run_in_reactor swallow exceptions
Consider the following code:
from __future__ import absolute_import, division, print_function
from crochet import no_setup, wait_for, run_in_reactor
no_setup()
from twisted.trial import unittest as unittest_twisted
import unittest as unittest_stdlib
class C(object):
@wait_for(1)
def wait_for(self):
raise Exception
@run_in_reactor
def run_in_reactor(self):
raise Exception
def vanilla(self):
raise Exception
class TestStdLib(unittest_stdlib.TestCase):
def test_wait_for(self):
C().wait_for()
def test_run_in_reactor(self):
C().run_in_reactor()
def test_vanilla(self):
C().vanilla()
class TestTwistedDefault(unittest_twisted.TestCase):
def test_wait_for(self):
C().wait_for()
def test_run_in_reactor(self):
C().run_in_reactor()
def test_vanilla(self):
C().vanilla()
class TestTwistedSync(unittest_twisted.SynchronousTestCase):
def test_wait_for(self):
C().wait_for()
def test_run_in_reactor(self):
C().run_in_reactor()
def test_vanilla(self):
C().vanilla()
The output of running it with trial on Python 2.7.8 (OS X) is as following:
test_t
TestStdLib
test_run_in_reactor ... [OK]
test_vanilla ... [ERROR]
test_wait_for ... [ERROR]
TestTwistedDefault
test_run_in_reactor ... [ERROR]
[ERROR]
test_vanilla ... [ERROR]
test_wait_for ... [ERROR]
[ERROR]
TestTwistedSync
test_run_in_reactor ... [OK]
test_vanilla ... [ERROR]
test_wait_for ... [ERROR]
===============================================================================
[ERROR]
Traceback (most recent call last):
File "/Users/hynek/.pyenv/versions/2.7.8/lib/python2.7/unittest/case.py", line 329, in run
testMethod()
File "/Users/hynek/Projects/ssce/test_t.py", line 32, in test_vanilla
C().vanilla()
File "/Users/hynek/Projects/ssce/test_t.py", line 21, in vanilla
raise Exception
exceptions.Exception:
test_t.TestStdLib.test_vanilla
===============================================================================
[ERROR]
Traceback (most recent call last):
File "/Users/hynek/.pyenv/versions/2.7.8/lib/python2.7/unittest/case.py", line 329, in run
testMethod()
File "/Users/hynek/Projects/ssce/test_t.py", line 26, in test_wait_for
C().wait_for()
File "/Users/hynek/.virtualenvs/sscce/lib/python2.7/site-packages/crochet/_eventloop.py", line 461, in wrapper
return eventual_result.wait(timeout)
File "/Users/hynek/.virtualenvs/sscce/lib/python2.7/site-packages/crochet/_eventloop.py", line 229, in wait
result = self._result(timeout)
File "/Users/hynek/.virtualenvs/sscce/lib/python2.7/site-packages/crochet/_eventloop.py", line 193, in _result
raise TimeoutError()
crochet._eventloop.TimeoutError:
test_t.TestStdLib.test_wait_for
===============================================================================
[ERROR]
Traceback (most recent call last):
File "/Users/hynek/.virtualenvs/sscce/lib/python2.7/site-packages/twisted/internet/defer.py", line 140, in maybeDeferred
result = f(*args, **kw)
File "/Users/hynek/Projects/ssce/test_t.py", line 18, in run_in_reactor
raise Exception
exceptions.Exception:
test_t.TestTwistedDefault.test_run_in_reactor
test_t.TestTwistedDefault.test_run_in_reactor
===============================================================================
[ERROR]
Traceback (most recent call last):
File "/Users/hynek/Projects/ssce/test_t.py", line 43, in test_vanilla
C().vanilla()
File "/Users/hynek/Projects/ssce/test_t.py", line 21, in vanilla
raise Exception
exceptions.Exception:
test_t.TestTwistedDefault.test_vanilla
===============================================================================
[ERROR]
Traceback (most recent call last):
File "/Users/hynek/Projects/ssce/test_t.py", line 37, in test_wait_for
C().wait_for()
File "/Users/hynek/.virtualenvs/sscce/lib/python2.7/site-packages/crochet/_eventloop.py", line 461, in wrapper
return eventual_result.wait(timeout)
File "/Users/hynek/.virtualenvs/sscce/lib/python2.7/site-packages/crochet/_eventloop.py", line 229, in wait
result = self._result(timeout)
File "/Users/hynek/.virtualenvs/sscce/lib/python2.7/site-packages/crochet/_eventloop.py", line 193, in _result
raise TimeoutError()
crochet._eventloop.TimeoutError:
test_t.TestTwistedDefault.test_wait_for
===============================================================================
[ERROR]
Traceback (most recent call last):
File "/Users/hynek/.virtualenvs/sscce/lib/python2.7/site-packages/twisted/internet/defer.py", line 140, in maybeDeferred
result = f(*args, **kw)
File "/Users/hynek/.virtualenvs/sscce/lib/python2.7/site-packages/crochet/_eventloop.py", line 458, in run
return function(*args, **kwargs)
File "/Users/hynek/Projects/ssce/test_t.py", line 14, in wait_for
raise Exception
exceptions.Exception:
test_t.TestTwistedDefault.test_wait_for
===============================================================================
[ERROR]
Traceback (most recent call last):
File "/Users/hynek/Projects/ssce/test_t.py", line 54, in test_vanilla
C().vanilla()
File "/Users/hynek/Projects/ssce/test_t.py", line 21, in vanilla
raise Exception
exceptions.Exception:
test_t.TestTwistedSync.test_vanilla
===============================================================================
[ERROR]
Traceback (most recent call last):
File "/Users/hynek/Projects/ssce/test_t.py", line 48, in test_wait_for
C().wait_for()
File "/Users/hynek/.virtualenvs/sscce/lib/python2.7/site-packages/crochet/_eventloop.py", line 461, in wrapper
return eventual_result.wait(timeout)
File "/Users/hynek/.virtualenvs/sscce/lib/python2.7/site-packages/crochet/_eventloop.py", line 229, in wait
result = self._result(timeout)
File "/Users/hynek/.virtualenvs/sscce/lib/python2.7/site-packages/crochet/_eventloop.py", line 193, in _result
raise TimeoutError()
crochet._eventloop.TimeoutError:
test_t.TestTwistedSync.test_wait_for
-------------------------------------------------------------------------------
Ran 9 tests in 3.020s
FAILED (errors=9, successes=2)
The output is the same on pypy.
I hope this is helpful.
I've never tested crochet on OS X... what does running the test suite tell you?
Tests pass skipping test_non_posix ... [SKIPPED]
with a rather non-sensical skip message of SIGCHLD is a POSIX-specific issue
.
That message could be better, I guess, but that's expected output.
OK, first problem with this example code is that you're calling no_setup()
: that's wrong. Trial doesn't really run the reactor in a useful way, so you need crochet to run it for you.
Once I switch no_setup()
to setup()
I get pretty much what is expected: no timeout errors, just Exceptions.
Also note that methods decorated with run_in_reactor
are async, so if you want to extract the exception you have to do something like C().run_in_reactor().wait(timeout=1)
.
If you change no_setup()
to setup()
does that fix your issue?
Yes and no: if I do that, I’ll get a fat traceback that reactor is already running.
If I do neither, I get:
Traceback (most recent call last):
File "/Users/hynek/Work/txepp/tests/test_sync_wrapper.py", line 35, in test_domain_check
ssp.domain_check(["test.com"])
File "/Users/hynek/Work/txepp/.tox/py27/lib/python2.7/site-packages/crochet/_eventloop.py", line 459, in wrapper
eventual_result = run()
File "/Users/hynek/Work/txepp/.tox/py27/lib/python2.7/site-packages/crochet/_eventloop.py", line 421, in wrapper
result = EventualResult(None, self._reactor)
exceptions.AttributeError: 'EventLoop' object has no attribute '_reactor'
How are you running tests - what command line? What version of trial
?
Somewhat seems to be related to what I'm seeing.
I'm actually trying to run tests in trial that test code which is decorated by wait_for.
Without any setup I get the error pasted by @hynek on the 11th Feb.
With no_setup()
the decorator blocks regardless as to whether the decorated function returns a deferred or not. When I ctrl-c I get this traceback:
[ERROR]
Traceback (most recent call last):
File "/home/dpn/.virtualenvs/inbox-api/lib/python2.7/site-packages/mock.py", line 1201, in patched
return func(*args, **keywargs)
File "/home/dpn/workspace/inbox-api/inboxadmin/views/tests/test_home.py", line 28, in test_get_url_info
return get_url_info("http://example.com")
File "/home/dpn/.virtualenvs/inbox-api/lib/python2.7/site-packages/crochet/_eventloop.py", line 461, in wrapper
return eventual_result.wait(timeout)
File "/home/dpn/.virtualenvs/inbox-api/lib/python2.7/site-packages/crochet/_eventloop.py", line 229, in wait
result = self._result(timeout)
File "/home/dpn/.virtualenvs/inbox-api/lib/python2.7/site-packages/crochet/_eventloop.py", line 189, in _result
self._result_set.wait(timeout)
File "/usr/lib64/python2.7/threading.py", line 621, in wait
self.__cond.wait(timeout)
File "/usr/lib64/python2.7/threading.py", line 359, in wait
_sleep(delay)
exceptions.KeyboardInterrupt:
If I use setup()
I get the following debug traceback:
[ERROR]
Traceback (most recent call last):
Failure: twisted.trial.util.DirtyReactorAggregateError: Reactor was unclean.
DelayedCalls: (set twisted.internet.base.DelayedCall.debug = True to debug)
<DelayedCall 0x7f86ff2c53f8 [0.0817131996155s] called=0 cancelled=0 LoopingCall<0.1>(reapAllProcesses, *(), **{})()
traceback at creation:
File "/usr/lib64/python2.7/threading.py", line 783, in __bootstrap
self.__bootstrap_inner()
File "/usr/lib64/python2.7/threading.py", line 810, in __bootstrap_inner
self.run()
File "/usr/lib64/python2.7/threading.py", line 763, in run
self.__target(*self.__args, **self.__kwargs)
File "/home/dpn/.virtualenvs/inbox-api/lib/python2.7/site-packages/crochet/_eventloop.py", line 382, in <lambda>
target=lambda: self._reactor.run(installSignalHandlers=False),
File "/home/dpn/.virtualenvs/inbox-api/lib/python2.7/site-packages/twisted/internet/base.py", line 1192, in run
self.mainLoop()
File "/home/dpn/.virtualenvs/inbox-api/lib/python2.7/site-packages/twisted/internet/base.py", line 1201, in mainLoop
self.runUntilCurrent()
File "/home/dpn/.virtualenvs/inbox-api/lib/python2.7/site-packages/twisted/internet/base.py", line 797, in runUntilCurrent
f(*a, **kw)
File "/home/dpn/.virtualenvs/inbox-api/lib/python2.7/site-packages/crochet/_eventloop.py", line 335, in _startReapingProcesses
lc.start(0.1, False)
File "/home/dpn/.virtualenvs/inbox-api/lib/python2.7/site-packages/twisted/internet/task.py", line 175, in start
self._reschedule()
File "/home/dpn/.virtualenvs/inbox-api/lib/python2.7/site-packages/twisted/internet/task.py", line 243, in _reschedule
self.call = self.clock.callLater(nextTime - currentTime, self)
>
Going to continue playing..
I suggest not using twisted.trial.unittest.TestCase
as base class when when writing crochet related tests, and specifically when you're testing the blocking APIs. Use unittest.TestCase
or twisted.trial.unittest.SynchronousTestCase
.
Actually @itamarst I totally misread the doc about wrapped_function - that's working as expected with no_setup()
now!
But, duly noted about not using the async test case.. thanks :)