From a1e8a26f33bf86061b3a5df9f2f0af1d54878ce5 Mon Sep 17 00:00:00 2001 From: semen603089 Date: Fri, 28 Jul 2023 23:09:20 -0400 Subject: [PATCH] `AsyncConnection[AsyncSession].aclose` implementation Added new methods :meth:`_asyncio.AsyncConnection.aclose` as a synonym for :meth:`_asyncio.AsyncConnection.close` and :meth:`_asyncio.AsyncSession.aclose` as a synonym for :meth:`_asyncio.AsyncSession.close` to the :class:`_asyncio.AsyncConnection` and :class:`_asyncio.AsyncSession` objects, to provide compatibility with Python standard library ``@contextlib.aclosing`` construct. Pull request courtesy Grigoriev Semyon. Fixes: #9698 Closes: #10106 Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/10106 Pull-request-sha: 9dbe87324d496323f1da4a131b4c3d485a8eea1b Change-Id: I861d1fd4586018c2bdd6b45d7918af4f7d48d193 --- doc/build/changelog/unreleased_20/9698.rst | 11 +++++++++++ lib/sqlalchemy/ext/asyncio/engine.py | 12 ++++++++++++ lib/sqlalchemy/ext/asyncio/scoping.py | 20 ++++++++++++++++++++ lib/sqlalchemy/ext/asyncio/session.py | 12 ++++++++++++ test/ext/asyncio/test_engine_py3k.py | 13 +++++++++++++ test/ext/asyncio/test_session_py3k.py | 11 +++++++++++ 6 files changed, 79 insertions(+) create mode 100644 doc/build/changelog/unreleased_20/9698.rst diff --git a/doc/build/changelog/unreleased_20/9698.rst b/doc/build/changelog/unreleased_20/9698.rst new file mode 100644 index 0000000000..b65faced70 --- /dev/null +++ b/doc/build/changelog/unreleased_20/9698.rst @@ -0,0 +1,11 @@ +.. change:: + :tags: usecase, asyncio + :tickets: 9698 + + Added new methods :meth:`_asyncio.AsyncConnection.aclose` as a synonym for + :meth:`_asyncio.AsyncConnection.close` and + :meth:`_asyncio.AsyncSession.aclose` as a synonym for + :meth:`_asyncio.AsyncSession.close` to the + :class:`_asyncio.AsyncConnection` and :class:`_asyncio.AsyncSession` + objects, to provide compatibility with Python standard library + ``@contextlib.aclosing`` construct. Pull request courtesy Grigoriev Semyon. diff --git a/lib/sqlalchemy/ext/asyncio/engine.py b/lib/sqlalchemy/ext/asyncio/engine.py index 594eb02a7d..deab97f659 100644 --- a/lib/sqlalchemy/ext/asyncio/engine.py +++ b/lib/sqlalchemy/ext/asyncio/engine.py @@ -476,6 +476,18 @@ class AsyncConnection( """ await greenlet_spawn(self._proxied.close) + async def aclose(self) -> None: + """A synonym for :meth:`_asyncio.AsyncConnection.close`. + + The :meth:`_asyncio.AsyncConnection.aclose` name is specifically + to support the Python standard library ``@contextlib.aclosing`` + context manager function. + + .. versionadded:: 2.0.20 + + """ + await self.close() + async def exec_driver_sql( self, statement: str, diff --git a/lib/sqlalchemy/ext/asyncio/scoping.py b/lib/sqlalchemy/ext/asyncio/scoping.py index d72b004685..ec99a20238 100644 --- a/lib/sqlalchemy/ext/asyncio/scoping.py +++ b/lib/sqlalchemy/ext/asyncio/scoping.py @@ -69,6 +69,7 @@ _T = TypeVar("_T", bound=Any) methods=[ "__contains__", "__iter__", + "aclose", "add", "add_all", "begin", @@ -300,6 +301,25 @@ class async_scoped_session(Generic[_AS]): return self._proxied.__iter__() + async def aclose(self) -> None: + r"""A synonym for :meth:`_asyncio.AsyncSession.close`. + + .. container:: class_bases + + Proxied for the :class:`_asyncio.AsyncSession` class on + behalf of the :class:`_asyncio.scoping.async_scoped_session` class. + + The :meth:`_asyncio.AsyncSession.aclose` name is specifically + to support the Python standard library ``@contextlib.aclosing`` + context manager function. + + .. versionadded:: 2.0.20 + + + """ # noqa: E501 + + return await self._proxied.aclose() + def add(self, instance: object, _warn: bool = True) -> None: r"""Place an object into this :class:`_orm.Session`. diff --git a/lib/sqlalchemy/ext/asyncio/session.py b/lib/sqlalchemy/ext/asyncio/session.py index 19a441ca61..02631cfebf 100644 --- a/lib/sqlalchemy/ext/asyncio/session.py +++ b/lib/sqlalchemy/ext/asyncio/session.py @@ -973,6 +973,18 @@ class AsyncSession(ReversibleProxy[Session]): """ await greenlet_spawn(self.sync_session.close) + async def aclose(self) -> None: + """A synonym for :meth:`_asyncio.AsyncSession.close`. + + The :meth:`_asyncio.AsyncSession.aclose` name is specifically + to support the Python standard library ``@contextlib.aclosing`` + context manager function. + + .. versionadded:: 2.0.20 + + """ + await self.close() + async def invalidate(self) -> None: """Close this Session, using connection invalidation. diff --git a/test/ext/asyncio/test_engine_py3k.py b/test/ext/asyncio/test_engine_py3k.py index bbbdbf512f..7289d5494e 100644 --- a/test/ext/asyncio/test_engine_py3k.py +++ b/test/ext/asyncio/test_engine_py3k.py @@ -1,4 +1,5 @@ import asyncio +import contextlib import inspect as stdlib_inspect from unittest.mock import patch @@ -663,6 +664,18 @@ class AsyncEngineTest(EngineFixture): with expect_raises(exc.TimeoutError): await engine.connect() + @testing.requires.python310 + @async_test + async def test_engine_aclose(self, async_engine): + users = self.tables.users + async with contextlib.aclosing(async_engine.connect()) as conn: + await conn.start() + trans = conn.begin() + await trans.start() + await conn.execute(delete(users)) + await trans.commit() + assert conn.closed + @testing.requires.queue_pool @async_test async def test_pool_exhausted_no_timeout(self, async_engine): diff --git a/test/ext/asyncio/test_session_py3k.py b/test/ext/asyncio/test_session_py3k.py index 228489349a..8fa174eeba 100644 --- a/test/ext/asyncio/test_session_py3k.py +++ b/test/ext/asyncio/test_session_py3k.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib from typing import List from typing import Optional @@ -148,6 +149,16 @@ class AsyncSessionQueryTest(AsyncFixture): result = await async_session.scalar(stmt) eq_(result, 7) + @testing.requires.python310 + @async_test + async def test_session_aclose(self, async_session): + User = self.classes.User + u = User(name="u") + async with contextlib.aclosing(async_session) as session: + session.add(u) + await session.commit() + assert async_session.sync_session.identity_map.values() == [] + @testing.combinations( ("scalars",), ("stream_scalars",), argnames="filter_" ) -- 2.47.3