classification
Title: Async magic methods in contextlib.closing
Type: enhancement Stage:
Components: Library (Lib) Versions: Python 3.10, Python 3.9
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: asvetlov, njs, serhiy.storchaka, uburuntu, xtreak, yselivanov
Priority: normal Keywords:

Created on 2020-07-02 18:22 by uburuntu, last changed 2020-08-11 00:58 by yselivanov.

Pull Requests
URL Status Linked Edit
PR 21285 open uburuntu, 2020-07-02 18:22
Messages (6)
msg372871 - (view) Author: Ramzan Bekbulatov (uburuntu) * Date: 2020-07-02 18:22
# Async magic methods in contextlib.closing

I think `__aenter__` and `__aexit__` methods should be added to `contextlib.closing`, so that we can use `contextlib.closing` in async code too.

For example:

```python3
class SomeAPI:
    ...

    async def request(self):
        pass

    async def close(self):
        await self.session.close()
        

async with closing(SomeAPI()) as api:
    response = await api.request()
    print(response)
```

Also these methods can be moved to another class (like `asyncclosing` along the lines of `asynccontextmanager`).
msg372873 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2020-07-02 19:03
And what happen when you accidentally use synchronous "with" instead of "async with" with closing()?

with closing(SomeAPI()) as api:
    ...

I think it is intentionally that different functions/methods/classes are used for synchronous and asynchronous operations.
msg372875 - (view) Author: Ramzan Bekbulatov (uburuntu) * Date: 2020-07-02 19:37
In this case:

```python3
class A:
    async def close(self):
        pass
    
with closing(A()):
    pass
```

Python will raise `RuntimeWarning: coroutine 'A.close' was never awaited`.

In another case:

```python3
class B:
    def close(self):
        pass
    
async with closing(B()):
    pass
```

Python will raise `TypeError: object NoneType can't be used in 'await' expression` (because it will try to await result of close method).

-----

I was surprised that `contextlib` has no async analogue of this `closing` class, because async scripts often use any kind of closings. Do you think it's better to extract to `asyncclosing` class?
msg372903 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python committer) Date: 2020-07-03 04:34
This seems to be a duplicate of issue40213 with a link to implementation in trio.
msg372904 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2020-07-03 05:15
Warning is not error. It may left unnoticed, especially if the code is executed on server. And in this particular case turning the warning into exception by setting warning filters does not help, because it would be raised in the context where exceptions are swallowed.
msg375160 - (view) Author: Yury Selivanov (yselivanov) * (Python committer) Date: 2020-08-11 00:58
I'm OK with adding this, but the close method should be `aclose()`
History
Date User Action Args
2020-08-11 00:58:14yselivanovsetnosy: + njs, asvetlov
2020-08-11 00:58:01yselivanovsetmessages: + msg375160
2020-07-03 05:15:01serhiy.storchakasetmessages: + msg372904
2020-07-03 04:34:27xtreaksetnosy: + xtreak
messages: + msg372903
2020-07-02 19:37:33uburuntusetmessages: + msg372875
2020-07-02 19:03:00serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg372873
2020-07-02 18:39:39xtreaksetnosy: + yselivanov
2020-07-02 18:22:53uburuntucreate