]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
PoolProxiedConnection support context protocol main
authorFederico Caselli <cfederico87@gmail.com>
Mon, 9 Feb 2026 21:47:19 +0000 (22:47 +0100)
committerFederico Caselli <cfederico87@gmail.com>
Wed, 11 Feb 2026 19:41:27 +0000 (20:41 +0100)
The connection object returned by :meth:`_engine.Engine.raw_connection`
now supports the context manager protocol, automatically returning the
connection to the pool when exiting the context.

Fixes: #13116
Change-Id: I51eb1fd61b772368f12a787e5f60db153a839e70

doc/build/changelog/unreleased_20/13116.rst [new file with mode: 0644]
lib/sqlalchemy/pool/base.py
test/engine/test_pool.py

diff --git a/doc/build/changelog/unreleased_20/13116.rst b/doc/build/changelog/unreleased_20/13116.rst
new file mode 100644 (file)
index 0000000..3e4f98c
--- /dev/null
@@ -0,0 +1,7 @@
+.. change::
+    :tags: usecase, engine
+    :tickets: 13116
+
+    The connection object returned by :meth:`_engine.Engine.raw_connection`
+    now supports the context manager protocol, automatically returning the
+    connection to the pool when exiting the context.
index 1c2f715624130dd6a34797fecc8f87a8ada68ad3..5ef01568a3d1150956fc74275facfc98d51bf088 100644 (file)
@@ -34,6 +34,7 @@ from .. import event
 from .. import exc
 from .. import log
 from .. import util
 from .. import exc
 from .. import log
 from .. import util
+from ..util.typing import Self
 
 if TYPE_CHECKING:
     from ..engine.interfaces import DBAPIConnection
 
 if TYPE_CHECKING:
     from ..engine.interfaces import DBAPIConnection
@@ -1122,6 +1123,13 @@ class PoolProxiedConnection(ManagesConnection):
         """
         raise NotImplementedError()
 
         """
         raise NotImplementedError()
 
+    def __enter__(self) -> Self:
+        return self
+
+    def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
+        self.close()
+        return None
+
 
 class _AdhocProxiedConnection(PoolProxiedConnection):
     """provides the :class:`.PoolProxiedConnection` interface for cases where
 
 class _AdhocProxiedConnection(PoolProxiedConnection):
     """provides the :class:`.PoolProxiedConnection` interface for cases where
index 6759390f50554d19e74b7ee4df02c059761ceb85..ab5cdccd8b59c7bb221cbbef1be56c7967506d2d 100644 (file)
@@ -31,6 +31,7 @@ from sqlalchemy.testing import is_not
 from sqlalchemy.testing import is_not_none
 from sqlalchemy.testing import is_true
 from sqlalchemy.testing import mock
 from sqlalchemy.testing import is_not_none
 from sqlalchemy.testing import is_true
 from sqlalchemy.testing import mock
+from sqlalchemy.testing.assertions import expect_raises_message
 from sqlalchemy.testing.engines import testing_engine
 from sqlalchemy.testing.util import gc_collect
 from sqlalchemy.testing.util import lazy_gc
 from sqlalchemy.testing.engines import testing_engine
 from sqlalchemy.testing.util import gc_collect
 from sqlalchemy.testing.util import lazy_gc
@@ -164,6 +165,25 @@ class PoolTest(PoolTestBase):
         assert not c2.info
         assert "foo2" in c.info
 
         assert not c2.info
         assert "foo2" in c.info
 
+    def test_raw_connection_context(self):
+        p = self._queuepool_fixture(pool_size=1, max_overflow=0)
+        e = create_engine("sqlite://", pool=p, _initialize=False)
+
+        eq_(p.checkedout(), 0)
+        conn = e.raw_connection()
+        eq_(p.checkedout(), 1)
+        with conn as wc:
+            eq_(p.checkedout(), 1)
+            is_(conn, wc)
+
+        eq_(p.checkedout(), 0)
+
+        with expect_raises_message(ValueError, "an error"):
+            with e.raw_connection() as wc:
+                eq_(p.checkedout(), 1)
+                raise ValueError("an error")
+        eq_(p.checkedout(), 0)
+
     def test_rec_info(self):
         p = self._queuepool_fixture(pool_size=1, max_overflow=0)
 
     def test_rec_info(self):
         p = self._queuepool_fixture(pool_size=1, max_overflow=0)