pythonpython-asynciopython-contextvars

async version of Context.run for context vars in python asyncio?


Python has the contextvars.copy_context() function which lets you store a copy of the current values of all the ContextVars that are currently active. Then later, you can run with all those values active by calling context_returned_by_copy_context.run(func). However, the run method is sync and expects a regular callable, not an async one. How can you run an async function with a context returned by copy_context?


Solution

  • lord_haffi's suggestion is apropos, but there is no need to create a new event loop since one should already be running:

    import asyncio
    import contextvars
    
    x = contextvars.ContextVar('x')
    
    async def async_fn():
        """An aysnc coroutine we would like to run with contextvars.Contex.run"""
    
        print(x.get())
    
    def fn():
        """ A non-coroutine that we will run with contextvars.Context.run"""
    
        loop = asyncio.get_running_loop()
        return loop.create_task(async_fn())
    
    async def demo(value):
        x.set(value)
        ctx = contextvars.copy_context()
        await ctx.run(fn)
    
    async def main():
        await asyncio.gather(demo(1), demo(2))
    
    asyncio.run(main())
    

    Prints:

    1
    2