From 213ee8b325e09bb6026c2495cf5810023f342f3f Mon Sep 17 00:00:00 2001 From: Ekin Dursun Date: Fri, 10 Nov 2023 18:33:41 +0300 Subject: [PATCH] Switch to more modern async idioms (#176) I converted AiofilesContextManager to an awaitable from a coroutine, and the interface was simplified as a result. In addition to that, open is now a proper async function and types.coroutine is not used anymore. --- README.md | 1 + src/aiofiles/base.py | 62 +++++------------------------ src/aiofiles/threadpool/__init__.py | 6 +-- 3 files changed, 12 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index 45bb554..d27799d 100644 --- a/README.md +++ b/README.md @@ -170,6 +170,7 @@ async def test_stuff(): - Import `os.link` conditionally to fix importing on android. [#175](https://github.com/Tinche/aiofiles/issues/175) - Remove spurious items from `aiofiles.os.__all__` when running on Windows. +- Switch to more modern async idioms: Remove types.coroutine and make AiofilesContextManager an awaitable instead a coroutine. #### 23.2.1 (2023-08-09) diff --git a/src/aiofiles/base.py b/src/aiofiles/base.py index 07f2c2e..64f7d6b 100644 --- a/src/aiofiles/base.py +++ b/src/aiofiles/base.py @@ -1,6 +1,6 @@ """Various base classes.""" -from types import coroutine -from collections.abc import Coroutine +from collections.abc import Awaitable +from contextlib import AbstractAsyncContextManager from asyncio import get_running_loop @@ -45,66 +45,22 @@ def _file(self, v): pass # discard writes -class _ContextManager(Coroutine): +class AiofilesContextManager(Awaitable, AbstractAsyncContextManager): + """An adjusted async context manager for aiofiles.""" + __slots__ = ("_coro", "_obj") def __init__(self, coro): self._coro = coro self._obj = None - def send(self, value): - return self._coro.send(value) - - def throw(self, typ, val=None, tb=None): - if val is None: - return self._coro.throw(typ) - elif tb is None: - return self._coro.throw(typ, val) - else: - return self._coro.throw(typ, val, tb) - - def close(self): - return self._coro.close() - - @property - def gi_frame(self): - return self._coro.gi_frame - - @property - def gi_running(self): - return self._coro.gi_running - - @property - def gi_code(self): - return self._coro.gi_code - - def __next__(self): - return self.send(None) - - @coroutine - def __iter__(self): - resp = yield from self._coro - return resp - def __await__(self): - resp = yield from self._coro - return resp - - async def __anext__(self): - resp = await self._coro - return resp - - async def __aenter__(self): - self._obj = await self._coro + if self._obj is None: + self._obj = yield from self._coro.__await__() return self._obj - async def __aexit__(self, exc_type, exc, tb): - self._obj.close() - self._obj = None - - -class AiofilesContextManager(_ContextManager): - """An adjusted async context manager for aiofiles.""" + async def __aenter__(self): + return await self async def __aexit__(self, exc_type, exc_val, exc_tb): await get_running_loop().run_in_executor( diff --git a/src/aiofiles/threadpool/__init__.py b/src/aiofiles/threadpool/__init__.py index a1cc673..e543283 100644 --- a/src/aiofiles/threadpool/__init__.py +++ b/src/aiofiles/threadpool/__init__.py @@ -10,7 +10,6 @@ FileIO, TextIOBase, ) -from types import coroutine from ..base import AiofilesContextManager from .binary import ( @@ -63,8 +62,7 @@ def open( ) -@coroutine -def _open( +async def _open( file, mode="r", buffering=-1, @@ -91,7 +89,7 @@ def _open( closefd=closefd, opener=opener, ) - f = yield from loop.run_in_executor(executor, cb) + f = await loop.run_in_executor(executor, cb) return wrap(f, loop=loop, executor=executor)