]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
`AsyncConnection[AsyncSession].aclose` implementation
authorsemen603089 <semen603089@mail.ru>
Sat, 29 Jul 2023 03:09:20 +0000 (23:09 -0400)
committermike bayer <mike_mp@zzzcomputing.com>
Mon, 31 Jul 2023 21:01:15 +0000 (21:01 +0000)
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 [new file with mode: 0644]
lib/sqlalchemy/ext/asyncio/engine.py
lib/sqlalchemy/ext/asyncio/scoping.py
lib/sqlalchemy/ext/asyncio/session.py
test/ext/asyncio/test_engine_py3k.py
test/ext/asyncio/test_session_py3k.py

diff --git a/doc/build/changelog/unreleased_20/9698.rst b/doc/build/changelog/unreleased_20/9698.rst
new file mode 100644 (file)
index 0000000..b65face
--- /dev/null
@@ -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.
index 594eb02a7df29d01d0e334cae8deb85a839516d8..deab97f6595fb7df41332bb4cec7336ad89ff7ac 100644 (file)
@@ -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,
index d72b00468543180698aaa9c357cc2742ada57194..ec99a20238825b2bb3893b91afe13cc03dc7b08d 100644 (file)
@@ -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`.
 
index 19a441ca613943ddc2c0b677e28b30e6a1a9991c..02631cfebf15466bfc5fe69059035080c1a2395b 100644 (file)
@@ -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.
 
index bbbdbf512f4b528026653e9a9700c198b86e2a60..7289d5494ebcaa172254fad8cc05915798c5ab0b 100644 (file)
@@ -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):
index 228489349a15c339cc285ff6836d79254255c9be..8fa174eebaaea5f0e3f8ed220f8e86cb03bd1922 100644 (file)
@@ -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_"
     )