This rule raises when using a regular with statement inside an async function with a context manager that implements the asynchronous
context manager protocol.
When working within an async function, it is important to maintain consistency with the asynchronous programming model. If a context manager
implements the asynchronous context manager protocol (defining __aenter__ and __aexit__ methods), it should be used with the
async with statement rather than the regular with statement.
The asynchronous context manager protocol is specifically designed to handle resources that may require asynchronous setup or teardown operations.
Using the regular with statement in an async context bypasses this intended asynchronous behavior.
Not following the proper async pattern can lead to:
Use the async with statement when working with asynchronous context managers.
class Resource:
def __enter__(self):
return self
def __exit__(self, exc_type, exc, tb):
...
async def __aenter__(self):
return self
async def __aexit__(self, exc_type, exc, tb):
...
async def main():
resource = Resource()
with resource: # Noncompliant: using 'with' in async function when async protocol is available
...
class Resource:
def __enter__(self):
return self
def __exit__(self, exc_type, exc, tb):
...
async def __aenter__(self):
return self
async def __aexit__(self, exc_type, exc, tb):
...
async def main():
async with Resource() as resource: # Compliant: using 'async with' in async function
...
The async with statement provides the proper way to use asynchronous context managers:
__aenter__ method and awaits its result as (if specified) __aexit__ method and awaits its completion, even if an exception occurs This ensures consistency with the async programming model and allows the context manager to perform any necessary asynchronous operations during setup and cleanup.