I would like to reboot this discussion (again). It feels to me we're getting farther and farther from solving any of the problems we might solve.
I think we need to give up on doing anything about generators; the use cases point in too many conflicting directions. So we should keep the semantics there, and if you don't want your numeric or decimal context to leak out of a generator, don't put `yield` inside `with`. (Yury and Stefan have both remarked that this is not a problem in practice, given that there are no bug reports or StackOverflow questions about this topic.)
Nobody understands async generators, so let's not worry about them.
That leaves coroutines (`async def` and `await`). It looks like we don't want to change the original semantics here either, *except* when a framework like asyncio or Twisted has some kind of abstraction for a "task". (I intentionally don't define tasks, but task switches should be explicit, e.g. via `await` or some API -- note that even gevent qualifies, since it only switches when you make a blocking call.)
The key things we want then are (a) an interface to get and set context variables whose API is independent from the framework in use (if any), and (b) a way for a framework to decide when context variables are copied, shared or reinitialized.
For (a) I like the API from PEP 550:
var = contextvars.ContextVar('description')
value = var.get()
var.set(value)