From: Daniele Varrazzo Date: Sun, 4 May 2025 21:26:26 +0000 (+0200) Subject: docs(pool): add documentation for close_returns X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1755398daf98755fd9496c0dfd966d7b6a6652a8;p=thirdparty%2Fpsycopg.git docs(pool): add documentation for close_returns --- diff --git a/docs/advanced/pool.rst b/docs/advanced/pool.rst index 6b41a7c05..98f556391 100644 --- a/docs/advanced/pool.rst +++ b/docs/advanced/pool.rst @@ -429,3 +429,70 @@ Metric Meaning ``connections_lost`` Number of connections lost identified by `~ConnectionPool.check()` or by the `!check` callback ======================= ===================================================== + + +.. _pool-sqlalchemy: + +Integration with SQLAlchemy +--------------------------- + +.. versionadded:: 3.3 + +If you want to use SQLAlchemy__ with psycopg's connection pool you can use the +SQLAlchemy's NullPool__ feature, using the pool's `~ConnectionPool.getconn` +as `!creator` function. However, SQLAlchemy expects that calling +`~psycopg.Connection.close()` on the connection will return the connection to +the pool, which is not Psycopg's default behaviour. + +.. __: https://sqlalchemy.org +.. __: https://docs.sqlalchemy.org/en/20/core/pooling.html#sqlalchemy.pool.NullPool + +Since `!psycopg_pool` version 3.3, the `!close_returns` parameter of the pool +allows to change this behaviour, telling its connections to return to the +pool, instead of closing, when `!close()` is called. + +For example: + +.. code:: python + + import sqlalchemy.pool + import psycopg_pool + + db_url = "postgresql://postgres:postgres@hostname:port/database" + + pgpool = psycopg_pool.ConnectionPool(conninfo=db_url, close_returns=True) + + engine = sqlalchemy.create_engine( + url=db_url.replace("postgresql://", "postgresql+psycopg://"), + poolclass=sqlalchemy.pool.NullPool, + creator=pgpool.getconn, + ) + +If you want to integrate the Psycopg pool with SQLAlchemy using a `!psycopg_pool` +version older than 3.3, you will need to create a subclass of the +`~psycopg.Connection` or `~psycopg.AsyncConnection` class, overriding the +`!close()` method, with an implementation similar to the following: + +.. code:: python + + class MyConnection(psycopg.AsyncConnection): + # If you need to subclass a sync connection, just drop the + # 'async' and 'await' keywords from this example. + async def close(self) -> None: + if pool := getattr(self, "_pool", None): + # Connection currently checked out from the pool. + # Instead of closing it, return it to the pool. + await pool.putconn(self) + else: + # Connection not part of any pool, or currently into the pool. + # Close the connection for real. + await super().close() + + +Using a connection implementing this method you will not need to specify +`!close_returns` in the pool constructor, but just `!connection_class`; the +example above would be modified as: + +.. code:: python + + pgpool = psycopg_pool.ConnectionPool(conninfo=db_url, connection_class=MyConnection) diff --git a/docs/api/pool.rst b/docs/api/pool.rst index aff683a5d..68cd3858b 100644 --- a/docs/api/pool.rst +++ b/docs/api/pool.rst @@ -98,6 +98,15 @@ The `!ConnectionPool` class want to perform a simple check. :type check: `Callable[[Connection], None]` + :param close_returns: If `!True`, calling `~psycopg.Connection.close()` on + the connection will not actually close it, but it + will return the connection to the pool, like in + `~ConnectionPool.putconn()`. Use it if you want to + use Psycopg pool with SQLAlchemy. See + :ref:`pool-sqlalchemy`. + + :type close_returns: `!bool`, default: `!False` + :param reset: A callback to reset a function after it has been returned to the pool. The connection is guaranteed to be passed to the `!reset()` function in "idle" state (no transaction). When @@ -166,9 +175,12 @@ The `!ConnectionPool` class added `!check` parameter to the constructor. .. versionchanged:: 3.2 - The class is generic and `!connection_class` provides types type + the class is generic and `!connection_class` provides types type variable. See :ref:`pool-generic`. + .. versionchanged:: 3.3 + added `!close_returns` parameter to the constructor. + .. warning:: At the moment, the default value for the `!open` parameter is `!True`; @@ -298,6 +310,9 @@ Only the functions and parameters with different signature from .. versionchanged:: 3.2 The `!reconnect_failed` parameter can be `!async`. + .. versionchanged:: 3.3 + added `!close_returns` parameter to the constructor. + .. warning:: Opening an async pool in the constructor (using `!open=True` on init) diff --git a/docs/news_pool.rst b/docs/news_pool.rst index 1e49e52a5..a2a463e0e 100644 --- a/docs/news_pool.rst +++ b/docs/news_pool.rst @@ -7,6 +7,16 @@ ``psycopg_pool`` release notes ============================== +Future releases +--------------- + +psycopg_pool 3.3.0 (unreleased) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Add `!close_returns` for :ref:`integration with SQLAlchemy ` + (:ticket:`#1046`). + + Current release --------------- diff --git a/psycopg_pool/psycopg_pool/pool.py b/psycopg_pool/psycopg_pool/pool.py index d5fd6eb0f..e67a32f24 100644 --- a/psycopg_pool/psycopg_pool/pool.py +++ b/psycopg_pool/psycopg_pool/pool.py @@ -65,7 +65,7 @@ class ConnectionPool(Generic[CT], BasePool): connection_class = cast(type[CT], PoolConnection) else: raise TypeError( - "Using 'close_returns=True' and a non-standard 'connection_class' requires psycopg 3.3 or newer." + "Using 'close_returns=True' and a non-standard 'connection_class' requires psycopg 3.3 or newer. Please check the docs at https://www.psycopg.org/psycopg3/docs/advanced/pool.html#pool-sqlalchemy for a workaround." ) self.connection_class = connection_class diff --git a/psycopg_pool/psycopg_pool/pool_async.py b/psycopg_pool/psycopg_pool/pool_async.py index ac4dfe83c..5731de9af 100644 --- a/psycopg_pool/psycopg_pool/pool_async.py +++ b/psycopg_pool/psycopg_pool/pool_async.py @@ -66,7 +66,9 @@ class AsyncConnectionPool(Generic[ACT], BasePool): else: raise TypeError( "Using 'close_returns=True' and a non-standard 'connection_class'" - " requires psycopg 3.3 or newer." + " requires psycopg 3.3 or newer. Please check the docs at" + " https://www.psycopg.org/psycopg3/docs/advanced/pool.html" + "#pool-sqlalchemy for a workaround." ) self.connection_class = connection_class