From: Daniele Varrazzo Date: Sun, 25 Jul 2021 00:22:55 +0000 (+0200) Subject: Fix idempotence of server side cursors close() X-Git-Tag: 3.0.dev2~36 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e3623962d3bd577b297c81a997224110a43da5e4;p=thirdparty%2Fpsycopg.git Fix idempotence of server side cursors close() --- diff --git a/psycopg/psycopg/server_cursor.py b/psycopg/psycopg/server_cursor.py index 201278f78..ec1859330 100644 --- a/psycopg/psycopg/server_cursor.py +++ b/psycopg/psycopg/server_cursor.py @@ -46,7 +46,7 @@ class ServerCursorHelper(Generic[ConnectionType, Row]): def _repr(self, cur: BaseCursor[ConnectionType, Row]) -> str: cls = f"{cur.__class__.__module__}.{cur.__class__.__qualname__}" info = pq.misc.connection_summary(cur._conn.pgconn) - if cur._closed: + if cur.closed: status = "closed" elif not cur.pgresult: status = "no result" @@ -194,7 +194,7 @@ class ServerCursor(BaseCursor["Connection[Any]", Row]): self.itersize: int = DEFAULT_ITERSIZE def __del__(self) -> None: - if not self._closed: + if not self.closed: warnings.warn( f"the server-side cursor {self} was deleted while still open." f" Please use 'with' or '.close()' to close the cursor properly", @@ -242,8 +242,10 @@ class ServerCursor(BaseCursor["Connection[Any]", Row]): Close the current cursor and free associated resources. """ with self._conn.lock: + if self.closed: + return self._conn.wait(self._helper._close_gen(self)) - self._close() + self._close() def execute( self, @@ -328,7 +330,7 @@ class AsyncServerCursor(BaseCursor["AsyncConnection[Any]", Row]): self.itersize: int = DEFAULT_ITERSIZE def __del__(self) -> None: - if not self._closed: + if not self.closed: warnings.warn( f"the server-side cursor {self} was deleted while still open." f" Please use 'with' or '.close()' to close the cursor properly", @@ -363,8 +365,10 @@ class AsyncServerCursor(BaseCursor["AsyncConnection[Any]", Row]): async def close(self) -> None: async with self._conn.lock: + if self.closed: + return await self._conn.wait(self._helper._close_gen(self)) - self._close() + self._close() async def execute( self, diff --git a/tests/test_server_cursor.py b/tests/test_server_cursor.py index 57c58b9a7..ecd61e9e8 100644 --- a/tests/test_server_cursor.py +++ b/tests/test_server_cursor.py @@ -67,6 +67,14 @@ def test_close(conn, recwarn, retries): assert not recwarn, [str(w.message) for w in recwarn.list] +def test_close_idempotent(conn): + cur = conn.cursor("foo") + cur.execute("select 1") + cur.fetchall() + cur.close() + cur.close() + + def test_close_noop(conn, recwarn, retries): for retry in retries: with retry: diff --git a/tests/test_server_cursor_async.py b/tests/test_server_cursor_async.py index 996c70a5c..af85b68e9 100644 --- a/tests/test_server_cursor_async.py +++ b/tests/test_server_cursor_async.py @@ -71,6 +71,14 @@ async def test_close(aconn, recwarn, retries): assert not recwarn, [str(w.message) for w in recwarn.list] +async def test_close_idempotent(aconn): + cur = aconn.cursor("foo") + await cur.execute("select 1") + await cur.fetchall() + await cur.close() + await cur.close() + + async def test_close_noop(aconn, recwarn, retries): async for retry in retries: with retry: