On 20 January 2014 15:59, Guido van Rossum <[email protected]> wrote:

> Yup, I think you've found a bug. wait_for() should definitely cancel
> the thing it's waiting for -- if you don't want that, you should call
> wait_for(shield(<coroutine_or_task>), <timeout>).
>
> It's likely that most of the wait_for() (or its unittests :-)
> implementation predates the rethinking of cancellation.
>
> Can you help fixing this before Python 3.4 beta 3 goes out 9Jan 26 I
> think)? I'm really busy through the 31st so I need help.
>

Sure, I think I can fix this.  How is the preferred way to submit patches
these days, codereview or googlecode issue, or both?

Thanks.

On Mon, Jan 20, 2014 at 7:41 AM, Gustavo Carneiro <[email protected]>
> wrote:
> > Hi.
> >
> > I spent a few hours chasing a nasty bug in either tulip or my code.  I
> got
> > this traceback:
> >
> > Traceback (most recent call last):
> >   File "/home/gjc/projects/mollytest/tests/base.py", line 63, in runTest
> >     return loop.run_until_complete(self.runTestTask())
> >   File "lib/asyncio/base_events.py", line 177, in run_until_complete
> >     return future.result()
> >   File "lib/asyncio/futures.py", line 236, in result
> >     raise self._exception
> >   File "lib/asyncio/tasks.py", line 279, in _step
> >     result = coro.send(value)
> >   File "tests/450-api-place-hide-exchange.py", line 42, in runTestTask
> >     lambda line: line[:2] == ['betslip_account_added', '3'] and line[5]
> ==
> > 'dummyex')),
> >   File "tests/450-api-place-hide-exchange.py", line 35, in wait_for_line
> >     line = yield from api.read_async_line()
> >   File "/home/gjc/projects/mollytest/mollyapiclient.py", line 68, in
> > read_async_line
> >     data = yield from read
> >   File "lib/asyncio/streams.py", line 321, in readline
> >     assert self._waiter is None
> > AssertionError
> >
> > After much debugging I discovered that:
> >
> >   1. That assertion fails when there are two concurrent StreamReader read
> > operations;
> >
> >   2. I eventually found out that the "previous" running read operation
> was
> > this one:
> >
> >                # self.async_reader is a StreamReader object
> >   data = yield from asyncio.wait_for(self.async_reader.readline(),
> timeout)
> >
> > In the above code, if the timeout actually happens, then
> > self.async_reader.readline(), which has been converted to a Task by
> > asyncio.wait_for(), is left running.  After the timeout, my script keeps
> > running, but the next call to StreamReader.readline() will fail and
> generate
> > the above traceback because the previous Task is still running.  I
> confirmed
> > this by adding a "fut.cancel()" call to tasks.wait_for() right before
> "raise
> > futures.TimeoutError()", which made the problem go away.
> >
> > I was a bit surprised by the behaviour of wait_for().  If wait_for()
> creates
> > a Task, I reckon it should be the one to cancel it when the timeout
> happens.
> > If you think shouldn't cancel a Task, then I think wait_for() shouldn't
> > create it in the first place, and so it should accept only Task as
> > parameter, and not coroutine (generator): in this case it's the
> application
> > programmer who should take care of cancelling the task on timeout.
> >
> > Thoughts?
> >
> > --
> > Gustavo J. A. M. Carneiro
> > Gambit Research LLC
> > "The universe is always one step beyond logic." -- Frank Herbert
>
>
>
> --
> --Guido van Rossum (python.org/~guido)
>



-- 
Gustavo J. A. M. Carneiro
Gambit Research LLC
"The universe is always one step beyond logic." -- Frank Herbert

Reply via email to