I have the following class
class MyService:
def __init__(self, my_api: MyAPI) -> None:
self._my_api = my_api
self._session_usage_count = 0
async def __aenter__(self) -> "MyService":
if not self._session_usage_count:
await self._my_api.init() # returns None
self._session_usage_count += 1
return self
async def __aexit__(self, *exc: Any) -> None:
self._session_usage_count -= 1
if not self._session_usage_count:
await self._my_api.close() # returns None
According to the doc both __aenter__ and __aexit__ must return an awaitable,
but in my case it's not. Also I read that __aexit__ returns bool implicitly.
So what should be the return type in my case?
TLDR: Annotating an async def statement with just the return type of awaiting it is fine.
An async def statement creates a callable that always returns an awaitable. Repeating this in the return type is thus not necessary.
from typing import Callable, Awaitable
async def greetings() -> str:
return "Hello World!"
c: Callable[..., Awaitable[str]] = greetings # mypy: Success: no issues found in 1 source file
This allows to use the same return type annotation for an async protocol as one would use for the corresponding sync protocol – e.g. __exit__/__aexit__ in this case.
The (async) Context Manager Protocol specifically only says that __exit__/__aexit__ "should return a true value" if "the method wishes to suppress the exception". It is perfectly fine to return another value/type, including None, if the exception should not be suppressed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With