[Python-Dev] asyncio: how to interrupt an async def w/ finally: ( e.g. Condition.wait() )

2015-12-19 Thread Matthias Urlichs
The following code has a problem: the generator returned by .wait() has a 
finally: section. When self.stopped is set, it still needs to run. As it is 
asynchronous (it needs to re-acquire the lock), I need to come up with a 
reliable way to wait for it. If I don't, .release() will throw an exception 
because the lock is still unlocked.

The best method to do this that I've come up with is the five marked lines.
I keep thinking there must be a better way to do this (taking into account 
that I have no idea whether the 'await r' part of this is even necessary).


```
class StopMe(BaseException):
pass
class Foo:
async dev some_method(self):
self.uptodate = asyncio.Condition()
self.stopped = asyncio.Future()
…
await self.uptodate.acquire()
try:
while self.some_condition():
w = self.uptodate.wait()
await asyncio.wait([w,self.stopped], loop=self.conn._loop, 
return_when=asyncio.FIRST_COMPLETED)
with contextlib.suppress(StopMe):  # FIXME?
r = w.throw(StopMe())  # FIXME?
if r is not None:  # FIXME?
await r# FIXME?
await w# FIXME?
finally:
self.uptodate.release()
```
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] asyncio: how to interrupt an async def w/ finally: ( e.g. Condition.wait() )

2015-12-19 Thread Matthias Urlichs
On 19.12.2015 20:25, Guido van Rossum wrote:
> Perhaps you can add a check for a simple boolean 'stop' flag to your
> condition check, and when you want to stop the loop you set that flag
> and then call notify() on the condition. Then you can follow the
> standard condition variable protocol instead of all this nonsense. :-)
Your example does not work.

>def stop_it(self):
>self.stopped = True
>self.uptodate.notify()

self.uptodate needs to be locked before I can call .notify() on it.
Creating a new task just for that seems like overkill, and I'd have to
add a generation counter to prevent a race condition. Doable, but ugly.

However, this doesn't fix the generic problem; Condition.wait() was just
what bit me today.
When a non-async generator goes out of scope, its finally: blocks will
execute. An async procedure call whose refcount reaches zero without
completing simply goes away; finally: blocks are *not* called and there
is *no* warning.
I consider that to be a bug.

-- 
-- Matthias Urlichs

___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] asyncio: how to interrupt an async def w/ finally: ( e.g. Condition.wait() )

2015-12-19 Thread Matthias Urlichs
On 20.12.2015 01:26, Kevin Conway wrote:
> async def coroutine():
> try:
> await Awaitable()
> await Awaitable()
> finally:
> print('finally')
Try adding another "await Awaitable()" after the "finally:".

I have to take back my "doesn't print an error" comment, however;
there's another reference to the Condition.wait() generator (the task
asyncio.wait() creates to wrap the generator in), and the "Task was
destroyed but it is pending!" message got delayed sufficiently that I
missed it. (Dying test cases tend to spew many of these.)

Testcase:

import asyncio
import gc
cond = asyncio.Condition()
loop = asyncio.get_event_loop()

async def main():
async with cond:
# asyncio.wait() does this, if we don't
w = asyncio.ensure_future(cond.wait())
await asyncio.wait([w],timeout=1)
print(gc.get_referrers(w))
loop.run_until_complete(main())

Time to refactor my code to do the wait/timeout outside the "async with
cond".

-- 
-- Matthias Urlichs

___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] iscoroutinefunction vs. coroutines

2017-03-09 Thread Matthias Urlichs
Hi,

Is this pattern

def foo():
return bar()
async def bar():
await 

async def async_main():
await foo()

considered to be valid?

The reason I'm asking is that some code out there likes to accept a
might-be-a-coroutine-function argument, using

def run_callback(fn):
if iscoroutinefunction(fn):
res = await fn()
else:
res = fn()

instead of

def run_callback(fn):
res = fn()
if iscoroutine(res):
res = await res()

The former obviously breaks when somebody combines these idioms and calls

run_callback(foo)

but I can't help but wonder whether the latter use might be deprecated, or
even warned about, in the future and/or with non-CPython implementations.

-- 
-- Matthias Urlichs


signature.asc
Description: Digital signature
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com