Issue 30831: Inconsistent or wrong documentation around Asynchronous Context Manager (original) (raw)
I was reading the following doc and got confused.
https://docs.python.org/3.7/reference/datamodel.html#object.aenter
According to the API doc itself (and original PEP 492), aenter() "is semantically similar to the enter(), with only difference that it must return an awaitable." aexit() has similar sentence that confuses me too.
PEP 492 also implies the (awaitable) object returned from obj.aenter() will be awaited immediately. In same manner, the (awaitable) object returned from obj.aexit() will be awaited too.
(From PEP 492)
async with EXPR as VAR: BLOCK
which is semantically equivalent to:
mgr = (EXPR) aexit = type(mgr).aexit aenter = type(mgr).aenter(mgr) exc = True
VAR = await aenter try: BLOCK except: if not await aexit(mgr, *sys.exc_info()): raise else: await aexit(mgr, None, None, None)
On the other hand, actual CPython implementation won't do that; it won't await the returned objects.
Moreover, the example shown in the API doc (AsyncContextManager) does NOT return awaitable as the doc itself suggests, but just await inside aenter() (and aexit()).
class AsyncContextManager: async def aenter(self): await log('entering context')
async def aexit(self, exc_type, exc, tb): await log('exiting context')
I'm not sure which is true; the doc saying "aenter() must return awaitable" is just incorrect, or CPython implementation has a bug. Actual source implies former. _ContextManagerMixin in asyncio.locks does not return awaitable at all, for example.
Anyway, I believe there are inconsistencies around here.
There's no inconsistency here and the docs are correct.
If you have a function:
async def foo(): pass
Then "foo()" call returns a "coroutine", which is an awaitable. So
async def aenter(): ...
always returns an awaitable (regardless if there's a return statement or not).
On the other hand, actual CPython implementation won't do that; it won't await the returned objects.
If always does await the returned object.