Make contextlib.contexmanager always works with sync or async functions

As I explained in `contextlib.contextmanager` exit before the start of a decorated function if we use it on async functions · Issue #114033 · python/cpython · GitHub, if you use an asynccontextmanager to decorate fun1 because it is async, you can’t use fun1 to decorate a sync function, moreover if you use the default contextmanager to decorate a function fun2 which is only sync and someone want to use to decorate an async function (fun3), no warning is raised but the closer of fun2 is called before fun3 this can be a major issue for example if the decorator create database transaction you will have :

transaction start
transaction end
fun3
...

So if fun3 has a bug, you will see that only when you have a bug … The transaction can’t help you to recover as it has been sucessfully finished with no error…

Here is a minimal code reproduction :

import asyncio
import contextlib


@contextlib.contextmanager
def sync_cm():
    print("sync open")
    yield
    print("sync close")

@sync_cm()
async def sync_async():
    print("sync_async")

the result is :

sync open
sync close
sync_async
1 Like