[Python-Dev] PEP 550 v4: coroutine policy

Antoine Pitrou solipsis at pitrou.net
Tue Aug 29 14:40:21 EDT 2017


On Mon, 28 Aug 2017 17:24:29 -0400
Yury Selivanov <yselivanov.ml at gmail.com> wrote:
> Long story short, I think we need to rollback our last decision to
> prohibit context propagation up the call stack in coroutines.  In PEP
> 550 v3 and earlier, the following snippet would work just fine:
> 
>    var = new_context_var()
> 
>    async def bar():
>        var.set(42)
> 
>    async def foo():
>        await bar()
>        assert var.get() == 42   # with previous PEP 550 semantics
> 
>    run_until_complete(foo())
> 
> But it would break if a user wrapped "await bar()" with "wait_for()":
> 
>    var = new_context_var()
> 
>    async def bar():
>        var.set(42)
> 
>    async def foo():
>        await wait_for(bar(), 1)
>        assert var.get() == 42  # AssertionError !!!
> 
>    run_until_complete(foo())
> 
[...]

> So I guess we have no other choice other than reverting this spec
> change for coroutines.  The very first example in this email should
> start working again.

What about the second one?  Why wouldn't the bar() coroutine inherit
the LC at the point it's instantiated (i.e. where the synchronous bar()
call is done)?

> This means that PEP 550 will have a caveat for async code: don't rely
> on context propagation up the call stack, unless you are writing
> __aenter__ and __aexit__ that are guaranteed to be called without
> being wrapped into a Task.

Hmm, sorry for being a bit slow, but I'm not sure what this
sentence implies.  How is the user supposed to know whether something
will be wrapped into a Task (short of being an expert in asyncio
internals perhaps)?

Actually, if could whip up an example of what you mean here, it would
be helpful I think :-)

> Thus I propose to stop associating PEP 550 concepts with
> (dynamic) scoping.

Agreed that dynamic scoping is a red herring here.

Regards

Antoine.




More information about the Python-Dev mailing list