From: Daniele Varrazzo Date: Sat, 2 Sep 2023 20:41:32 +0000 (+0100) Subject: feat(connection): add set_autocommit() and similar methods X-Git-Tag: pool-3.2.0~12^2~43 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ed9109dd44d0c0092ba0369addd54985b65bf4d5;p=thirdparty%2Fpsycopg.git feat(connection): add set_autocommit() and similar methods --- diff --git a/docs/api/connections.rst b/docs/api/connections.rst index db25382b3..a607f07fa 100644 --- a/docs/api/connections.rst +++ b/docs/api/connections.rst @@ -208,6 +208,10 @@ The `!Connection` class ones: you should call `!await` `~AsyncConnection.set_autocommit` :samp:`({value})` instead. + .. automethod:: set_autocommit + + .. versionadded:: 3.2 + The following three properties control the characteristics of new transactions. See :ref:`transaction-characteristics` for details. @@ -219,6 +223,10 @@ The `!Connection` class .. __: https://www.postgresql.org/docs/current/runtime-config-client.html #GUC-DEFAULT-TRANSACTION-ISOLATION + .. automethod:: set_isolation_level + + .. versionadded:: 3.2 + .. autoattribute:: read_only `!None` means use the default set in the default_transaction_read_only__ @@ -227,6 +235,10 @@ The `!Connection` class .. __: https://www.postgresql.org/docs/current/runtime-config-client.html #GUC-DEFAULT-TRANSACTION-READ-ONLY + .. automethod:: set_read_only + + .. versionadded:: 3.2 + .. autoattribute:: deferrable `!None` means use the default set in the default_transaction_deferrable__ @@ -235,6 +247,10 @@ The `!Connection` class .. __: https://www.postgresql.org/docs/current/runtime-config-client.html #GUC-DEFAULT-TRANSACTION-DEFERRABLE + .. automethod:: set_deferrable + + .. versionadded:: 3.2 + .. rubric:: Checking and configuring the connection state diff --git a/docs/basic/transactions.rst b/docs/basic/transactions.rst index fe05f9f3e..abcecc9d2 100644 --- a/docs/basic/transactions.rst +++ b/docs/basic/transactions.rst @@ -328,6 +328,10 @@ In order to set these parameters you can use the connection attributes can only be changed if there isn't a transaction already active on the connection. +.. versionadded:: 3.2 + Added methods equivalent to setting the properties (such as + `~Connection.set_isolation_level()`) on sync connections too. + .. warning:: Applications running at `~IsolationLevel.REPEATABLE_READ` or diff --git a/docs/news.rst b/docs/news.rst index eca84e673..f7b227e9e 100644 --- a/docs/news.rst +++ b/docs/news.rst @@ -17,6 +17,8 @@ Psycopg 3.2 (unreleased) (:ticket:`#332`). - Add :ref:`raw-query-cursors` to execute queries using placeholders in PostgreSQL format (`$1`, `$2`...) (:ticket:`#560`). +- Add `~Connection.set_autocommit()` on sync connections, and similar + transaction control methods available on the async connections. - Add support for libpq functions to close prepared statements and portals introduced in libpq v17 (:ticket:`#603`). - Disable receiving more than one result on the same cursor in pipeline mode, diff --git a/psycopg/psycopg/connection.py b/psycopg/psycopg/connection.py index 73724f616..4075c1fe4 100644 --- a/psycopg/psycopg/connection.py +++ b/psycopg/psycopg/connection.py @@ -369,18 +369,34 @@ class Connection(BaseConnection[Row]): return waiting.wait_conn(gen, timeout=timeout) def _set_autocommit(self, value: bool) -> None: + self.set_autocommit(value) + + def set_autocommit(self, value: bool) -> None: + """Method version of the `~Connection.autocommit` setter.""" with self.lock: self.wait(self._set_autocommit_gen(value)) def _set_isolation_level(self, value: Optional[IsolationLevel]) -> None: + self.set_isolation_level(value) + + def set_isolation_level(self, value: Optional[IsolationLevel]) -> None: + """Method version of the `~Connection.isolation_level` setter.""" with self.lock: self.wait(self._set_isolation_level_gen(value)) def _set_read_only(self, value: Optional[bool]) -> None: + self.set_read_only(value) + + def set_read_only(self, value: Optional[bool]) -> None: + """Method version of the `~Connection.read_only` setter.""" with self.lock: self.wait(self._set_read_only_gen(value)) def _set_deferrable(self, value: Optional[bool]) -> None: + self.set_deferrable(value) + + def set_deferrable(self, value: Optional[bool]) -> None: + """Method version of the `~Connection.deferrable` setter.""" with self.lock: self.wait(self._set_deferrable_gen(value)) diff --git a/tests/_test_connection.py b/tests/_test_connection.py index 8ce090293..296a7f7f4 100644 --- a/tests/_test_connection.py +++ b/tests/_test_connection.py @@ -9,22 +9,6 @@ import pytest import psycopg -async def aconn_set(conn, param, value): - """Equivalent of 'await conn.set_param(value)' - - Converted to conn_set in sync tests. - """ - await getattr(conn, f"set_{param}")(value) - - -def conn_set(conn, param, value): - """Equivalent of 'conn.param = value'. - - Converted from aconn_set in sync tests. - """ - setattr(conn, param, value) - - @pytest.fixture def testctx(svcconn): svcconn.execute("create table if not exists testctx (id int primary key)") diff --git a/tests/test_connection.py b/tests/test_connection.py index 914bfa647..f995e5b0b 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -16,7 +16,7 @@ from psycopg.conninfo import conninfo_to_dict, make_conninfo from .utils import gc_collect, is_async from ._test_cursor import my_row_factory from ._test_connection import tx_params, tx_params_isolation, tx_values_map -from ._test_connection import conninfo_params_timeout, conn_set +from ._test_connection import conninfo_params_timeout from ._test_connection import testctx # noqa: F401 # fixture from .test_adapt import make_bin_dumper, make_dumper @@ -320,6 +320,25 @@ def test_autocommit_readonly_property(conn): def test_autocommit(conn): assert conn.autocommit is False + conn.set_autocommit(True) + assert conn.autocommit + cur = conn.cursor() + cur.execute("select 1") + assert cur.fetchone() == (1,) + assert conn.pgconn.transaction_status == conn.TransactionStatus.IDLE + + conn.set_autocommit("") + assert isinstance(conn.autocommit, bool) + assert conn.autocommit is False + + conn.set_autocommit("yeah") + assert isinstance(conn.autocommit, bool) + assert conn.autocommit is True + + +@pytest.mark.skipif(is_async(__name__), reason="sync test only") +def test_autocommit_property(conn): + assert conn.autocommit is False conn.autocommit = True assert conn.autocommit @@ -349,7 +368,7 @@ def test_autocommit_intrans(conn): assert cur.fetchone() == (1,) assert conn.pgconn.transaction_status == conn.TransactionStatus.INTRANS with pytest.raises(psycopg.ProgrammingError): - conn.autocommit = True + conn.set_autocommit(True) assert not conn.autocommit @@ -359,7 +378,7 @@ def test_autocommit_inerror(conn): cur.execute("meh") assert conn.pgconn.transaction_status == conn.TransactionStatus.INERROR with pytest.raises(psycopg.ProgrammingError): - conn.autocommit = True + conn.set_autocommit(True) assert not conn.autocommit @@ -367,7 +386,7 @@ def test_autocommit_unknown(conn): conn.close() assert conn.pgconn.transaction_status == conn.TransactionStatus.UNKNOWN with pytest.raises(psycopg.OperationalError): - conn.autocommit = True + conn.set_autocommit(True) assert not conn.autocommit @@ -481,7 +500,7 @@ def test_notify_handlers(conn): conn.add_notify_handler(cb1) conn.add_notify_handler(lambda n: nots2.append(n)) - conn.autocommit = True + conn.set_autocommit(True) cur = conn.cursor() cur.execute("listen foo") cur.execute("notify foo, 'n1'") @@ -627,9 +646,9 @@ def test_transaction_param_readonly_property(conn, param): @pytest.mark.parametrize("autocommit", [True, False]) @pytest.mark.parametrize("param", tx_params_isolation) def test_set_transaction_param_implicit(conn, param, autocommit): - conn.autocommit = autocommit + conn.set_autocommit(autocommit) for value in param.values: - conn_set(conn, param.name, value) + getattr(conn, f"set_{param.name}")(value) cur = conn.execute( "select current_setting(%s), current_setting(%s)", [f"transaction_{param.guc}", f"default_transaction_{param.guc}"], @@ -651,13 +670,13 @@ def test_set_transaction_param_reset(conn, param): conn.commit() for value in param.values: - conn_set(conn, param.name, value) + getattr(conn, f"set_{param.name}")(value) cur = conn.execute("select current_setting(%s)", [f"transaction_{param.guc}"]) (pgval,) = cur.fetchone() assert tx_values_map[pgval] == value conn.rollback() - conn_set(conn, param.name, None) + getattr(conn, f"set_{param.name}")(None) cur = conn.execute("select current_setting(%s)", [f"transaction_{param.guc}"]) (pgval,) = cur.fetchone() assert tx_values_map[pgval] == tx_values_map[param.non_default] @@ -667,9 +686,9 @@ def test_set_transaction_param_reset(conn, param): @pytest.mark.parametrize("autocommit", [True, False]) @pytest.mark.parametrize("param", tx_params_isolation) def test_set_transaction_param_block(conn, param, autocommit): - conn.autocommit = autocommit + conn.set_autocommit(autocommit) for value in param.values: - conn_set(conn, param.name, value) + getattr(conn, f"set_{param.name}")(value) with conn.transaction(): cur = conn.execute( "select current_setting(%s)", [f"transaction_{param.guc}"] @@ -683,7 +702,7 @@ def test_set_transaction_param_not_intrans_implicit(conn, param): conn.execute("select 1") value = param.values[0] with pytest.raises(psycopg.ProgrammingError): - conn_set(conn, param.name, value) + getattr(conn, f"set_{param.name}")(value) @pytest.mark.parametrize("param", tx_params) @@ -691,17 +710,32 @@ def test_set_transaction_param_not_intrans_block(conn, param): value = param.values[0] with conn.transaction(): with pytest.raises(psycopg.ProgrammingError): - conn_set(conn, param.name, value) + getattr(conn, f"set_{param.name}")(value) @pytest.mark.parametrize("param", tx_params) def test_set_transaction_param_not_intrans_external(conn, param): value = param.values[0] - - conn.autocommit = True + conn.set_autocommit(True) conn.execute("begin") with pytest.raises(psycopg.ProgrammingError): - conn_set(conn, param.name, value) + getattr(conn, f"set_{param.name}")(value) + + +@pytest.mark.skipif(is_async(__name__), reason="sync test only") +@pytest.mark.crdb("skip", reason="transaction isolation") +def test_set_transaction_param_all_property(conn): + params: List[Any] = tx_params[:] + params[2] = params[2].values[0] + + for param in params: + value = param.values[0] + setattr(conn, param.name, value) + + for param in params: + cur = conn.execute("select current_setting(%s)", [f"transaction_{param.guc}"]) + pgval = cur.fetchone()[0] + assert tx_values_map[pgval] == value @pytest.mark.crdb("skip", reason="transaction isolation") @@ -711,7 +745,7 @@ def test_set_transaction_param_all(conn): for param in params: value = param.values[0] - conn_set(conn, param.name, value) + getattr(conn, f"set_{param.name}")(value) for param in params: cur = conn.execute("select current_setting(%s)", [f"transaction_{param.guc}"]) @@ -720,6 +754,22 @@ def test_set_transaction_param_all(conn): def test_set_transaction_param_strange(conn): + for val in ("asdf", 0, 5): + with pytest.raises(ValueError): + conn.set_isolation_level(val) + + conn.set_isolation_level(psycopg.IsolationLevel.SERIALIZABLE.value) + assert conn.isolation_level is psycopg.IsolationLevel.SERIALIZABLE + + conn.set_read_only(1) + assert conn.read_only is True + + conn.set_deferrable(0) + assert conn.deferrable is False + + +@pytest.mark.skipif(is_async(__name__), reason="sync test only") +def test_set_transaction_param_strange_property(conn): for val in ("asdf", 0, 5): with pytest.raises(ValueError): conn.isolation_level = val diff --git a/tests/test_connection_async.py b/tests/test_connection_async.py index b9a0c005e..7830cf9a2 100644 --- a/tests/test_connection_async.py +++ b/tests/test_connection_async.py @@ -13,7 +13,7 @@ from psycopg.conninfo import conninfo_to_dict, make_conninfo from .utils import gc_collect, is_async from ._test_cursor import my_row_factory from ._test_connection import tx_params, tx_params_isolation, tx_values_map -from ._test_connection import conninfo_params_timeout, aconn_set +from ._test_connection import conninfo_params_timeout from ._test_connection import testctx # noqa: F401 # fixture from .test_adapt import make_bin_dumper, make_dumper @@ -334,6 +334,26 @@ async def test_autocommit(aconn): assert aconn.autocommit is True +@pytest.mark.skipif(is_async(__name__), reason="sync test only") +def test_autocommit_property(conn): + assert conn.autocommit is False + + conn.autocommit = True + assert conn.autocommit + cur = conn.cursor() + cur.execute("select 1") + assert cur.fetchone() == (1,) + assert conn.pgconn.transaction_status == conn.TransactionStatus.IDLE + + conn.autocommit = "" + assert isinstance(conn.autocommit, bool) + assert conn.autocommit is False + + conn.autocommit = "yeah" + assert isinstance(conn.autocommit, bool) + assert conn.autocommit is True + + async def test_autocommit_connect(aconn_cls, dsn): aconn = await aconn_cls.connect(dsn, autocommit=True) assert aconn.autocommit @@ -630,7 +650,7 @@ async def test_transaction_param_readonly_property(aconn, param): async def test_set_transaction_param_implicit(aconn, param, autocommit): await aconn.set_autocommit(autocommit) for value in param.values: - await aconn_set(aconn, param.name, value) + await getattr(aconn, f"set_{param.name}")(value) cur = await aconn.execute( "select current_setting(%s), current_setting(%s)", [f"transaction_{param.guc}", f"default_transaction_{param.guc}"], @@ -652,7 +672,7 @@ async def test_set_transaction_param_reset(aconn, param): await aconn.commit() for value in param.values: - await aconn_set(aconn, param.name, value) + await getattr(aconn, f"set_{param.name}")(value) cur = await aconn.execute( "select current_setting(%s)", [f"transaction_{param.guc}"] ) @@ -660,7 +680,7 @@ async def test_set_transaction_param_reset(aconn, param): assert tx_values_map[pgval] == value await aconn.rollback() - await aconn_set(aconn, param.name, None) + await getattr(aconn, f"set_{param.name}")(None) cur = await aconn.execute( "select current_setting(%s)", [f"transaction_{param.guc}"] ) @@ -674,7 +694,7 @@ async def test_set_transaction_param_reset(aconn, param): async def test_set_transaction_param_block(aconn, param, autocommit): await aconn.set_autocommit(autocommit) for value in param.values: - await aconn_set(aconn, param.name, value) + await getattr(aconn, f"set_{param.name}")(value) async with aconn.transaction(): cur = await aconn.execute( "select current_setting(%s)", [f"transaction_{param.guc}"] @@ -688,7 +708,7 @@ async def test_set_transaction_param_not_intrans_implicit(aconn, param): await aconn.execute("select 1") value = param.values[0] with pytest.raises(psycopg.ProgrammingError): - await aconn_set(aconn, param.name, value) + await getattr(aconn, f"set_{param.name}")(value) @pytest.mark.parametrize("param", tx_params) @@ -696,7 +716,7 @@ async def test_set_transaction_param_not_intrans_block(aconn, param): value = param.values[0] async with aconn.transaction(): with pytest.raises(psycopg.ProgrammingError): - await aconn_set(aconn, param.name, value) + await getattr(aconn, f"set_{param.name}")(value) @pytest.mark.parametrize("param", tx_params) @@ -705,7 +725,23 @@ async def test_set_transaction_param_not_intrans_external(aconn, param): await aconn.set_autocommit(True) await aconn.execute("begin") with pytest.raises(psycopg.ProgrammingError): - await aconn_set(aconn, param.name, value) + await getattr(aconn, f"set_{param.name}")(value) + + +@pytest.mark.skipif(is_async(__name__), reason="sync test only") +@pytest.mark.crdb("skip", reason="transaction isolation") +def test_set_transaction_param_all_property(conn): + params: List[Any] = tx_params[:] + params[2] = params[2].values[0] + + for param in params: + value = param.values[0] + setattr(conn, param.name, value) + + for param in params: + cur = conn.execute("select current_setting(%s)", [f"transaction_{param.guc}"]) + pgval = cur.fetchone()[0] + assert tx_values_map[pgval] == value @pytest.mark.crdb("skip", reason="transaction isolation") @@ -715,7 +751,7 @@ async def test_set_transaction_param_all(aconn): for param in params: value = param.values[0] - await aconn_set(aconn, param.name, value) + await getattr(aconn, f"set_{param.name}")(value) for param in params: cur = await aconn.execute( @@ -740,6 +776,22 @@ async def test_set_transaction_param_strange(aconn): assert aconn.deferrable is False +@pytest.mark.skipif(is_async(__name__), reason="sync test only") +def test_set_transaction_param_strange_property(conn): + for val in ("asdf", 0, 5): + with pytest.raises(ValueError): + conn.isolation_level = val + + conn.isolation_level = psycopg.IsolationLevel.SERIALIZABLE.value + assert conn.isolation_level is psycopg.IsolationLevel.SERIALIZABLE + + conn.read_only = 1 + assert conn.read_only is True + + conn.deferrable = 0 + assert conn.deferrable is False + + @pytest.mark.parametrize("dsn, kwargs, exp", conninfo_params_timeout) async def test_get_connection_params(aconn_cls, dsn, kwargs, exp, setpgenv): setpgenv({}) diff --git a/tests/test_copy.py b/tests/test_copy.py index f4deaf98b..5ab25a862 100644 --- a/tests/test_copy.py +++ b/tests/test_copy.py @@ -213,7 +213,7 @@ def test_copy_in_buffers_pg_error(conn): def test_copy_bad_result(conn): - conn.autocommit = True + conn.set_autocommit(True) cur = conn.cursor() diff --git a/tests/test_cursor.py b/tests/test_cursor.py index 5377d0d1e..f459b4943 100644 --- a/tests/test_cursor.py +++ b/tests/test_cursor.py @@ -708,7 +708,7 @@ def test_stream_error_tx(conn): def test_stream_error_notx(conn): - conn.autocommit = True + conn.set_autocommit(True) cur = conn.cursor() with pytest.raises(psycopg.ProgrammingError): for rec in cur.stream("wat"): @@ -741,7 +741,7 @@ def test_stream_error_python_consumed(conn): @pytest.mark.parametrize("autocommit", [False, True]) def test_stream_close(conn, autocommit): - conn.autocommit = autocommit + conn.set_autocommit(autocommit) cur = conn.cursor() with pytest.raises(psycopg.OperationalError): for rec in cur.stream("select generate_series(1, 3)"): @@ -815,7 +815,7 @@ def test_message_0x33(conn): notices = [] conn.add_notice_handler(lambda diag: notices.append(diag.message_primary)) - conn.autocommit = True + conn.set_autocommit(True) with conn.pipeline(): cur = conn.execute("select 'test'") assert cur.fetchone() == ("test",) diff --git a/tests/test_pipeline.py b/tests/test_pipeline.py index 35028795f..da46dbc40 100644 --- a/tests/test_pipeline.py +++ b/tests/test_pipeline.py @@ -143,7 +143,7 @@ def test_pipeline_processed_at_exit(conn): def test_pipeline_errors_processed_at_exit(conn): - conn.autocommit = True + conn.set_autocommit(True) with pytest.raises(e.UndefinedTable): with conn.pipeline(): conn.execute("select * from nosuchtable") @@ -172,7 +172,7 @@ def test_pipeline(conn): def test_autocommit(conn): - conn.autocommit = True + conn.set_autocommit(True) with conn.pipeline(), conn.cursor() as c: c.execute("select 1") @@ -181,7 +181,7 @@ def test_autocommit(conn): def test_pipeline_aborted(conn): - conn.autocommit = True + conn.set_autocommit(True) with conn.pipeline() as p: c1 = conn.execute("select 1") with pytest.raises(e.UndefinedTable): @@ -217,7 +217,7 @@ def test_sync_syncs_results(conn): @pytest.mark.flakey("assert rarely fails randomly in CI blocking release") def test_sync_syncs_errors(conn): - conn.autocommit = True + conn.set_autocommit(True) with conn.pipeline() as p: conn.execute("select 1 from nosuchtable") with pytest.raises(e.UndefinedTable): @@ -272,7 +272,7 @@ def test_errors_raised_on_nested_transaction_exit(conn): def test_implicit_transaction(conn): - conn.autocommit = True + conn.set_autocommit(True) with conn.pipeline(): assert conn.pgconn.transaction_status == pq.TransactionStatus.IDLE conn.execute("select 'before'") @@ -319,7 +319,7 @@ def test_fetch_no_result(conn): def test_executemany(conn): - conn.autocommit = True + conn.set_autocommit(True) conn.execute("drop table if exists execmanypipeline") conn.execute( "create unlogged table execmanypipeline (id serial primary key, num integer)" @@ -339,7 +339,7 @@ def test_executemany(conn): def test_executemany_no_returning(conn): - conn.autocommit = True + conn.set_autocommit(True) conn.execute("drop table if exists execmanypipelinenoreturning") conn.execute( """create unlogged table execmanypipelinenoreturning @@ -361,7 +361,7 @@ def test_executemany_no_returning(conn): @pytest.mark.crdb("skip", reason="temp tables") def test_executemany_trace(conn, trace): - conn.autocommit = True + conn.set_autocommit(True) cur = conn.cursor() cur.execute("create temp table trace (id int)") t = trace.trace(conn) @@ -379,7 +379,7 @@ def test_executemany_trace(conn, trace): @pytest.mark.crdb("skip", reason="temp tables") def test_executemany_trace_returning(conn, trace): - conn.autocommit = True + conn.set_autocommit(True) cur = conn.cursor() cur.execute("create temp table trace (id int)") t = trace.trace(conn) @@ -401,7 +401,7 @@ def test_executemany_trace_returning(conn, trace): def test_prepared(conn): - conn.autocommit = True + conn.set_autocommit(True) with conn.pipeline(): c1 = conn.execute("select %s::int", [10], prepare=True) c2 = conn.execute( @@ -435,8 +435,7 @@ def test_prepare_error(conn): An invalid prepared statement, in a pipeline, should be discarded at exit and not reused. """ - - conn.autocommit = True + conn.set_autocommit(True) stmt = "INSERT INTO nosuchtable(data) VALUES (%s)" with pytest.raises(psycopg.errors.UndefinedTable): with conn.pipeline(): @@ -514,7 +513,7 @@ def test_outer_transaction_error(conn): def test_rollback_explicit(conn): - conn.autocommit = True + conn.set_autocommit(True) with conn.pipeline(): with pytest.raises(e.DivisionByZero): cur = conn.execute("select 1 / %s", [0]) @@ -524,7 +523,7 @@ def test_rollback_explicit(conn): def test_rollback_transaction(conn): - conn.autocommit = True + conn.set_autocommit(True) with pytest.raises(e.DivisionByZero): with conn.pipeline(): with conn.transaction(): @@ -538,7 +537,7 @@ def test_message_0x33(conn): notices = [] conn.add_notice_handler(lambda diag: notices.append(diag.message_primary)) - conn.autocommit = True + conn.set_autocommit(True) with conn.pipeline(): cur = conn.execute("select 'test'") assert cur.fetchone() == ("test",) @@ -581,7 +580,7 @@ def test_concurrency(conn): conn.execute("update accessed set value = now()") return cur - conn.autocommit = True + conn.set_autocommit(True) (before,) = conn.execute("select value from accessed").fetchone() diff --git a/tests/test_prepared.py b/tests/test_prepared.py index eb34a1b11..c639f8ac3 100644 --- a/tests/test_prepared.py +++ b/tests/test_prepared.py @@ -103,7 +103,7 @@ def test_no_prepare_multi_with_drop(conn): def test_no_prepare_error(conn): - conn.autocommit = True + conn.set_autocommit(True) for i in range(10): with pytest.raises(conn.ProgrammingError): conn.execute("select wat") diff --git a/tests/test_tpc.py b/tests/test_tpc.py index c5bbc34f5..41023ccc8 100644 --- a/tests/test_tpc.py +++ b/tests/test_tpc.py @@ -163,8 +163,7 @@ class TestTPC: def test_recovered_xids(self, conn, tpc): # insert a few test xns - - conn.autocommit = True + conn.set_autocommit(True) cur = conn.cursor() cur.execute("begin; prepare transaction '1-foo'") cur.execute("begin; prepare transaction '2-bar'") diff --git a/tests/test_transaction.py b/tests/test_transaction.py index b73e6c87f..a82a8f9c7 100644 --- a/tests/test_transaction.py +++ b/tests/test_transaction.py @@ -149,20 +149,19 @@ def test_prohibits_use_of_commit_rollback_autocommit(conn): or the autocommit setting on the connection, as this would interfere with the transaction scope being managed by the Transaction block. """ - - conn.autocommit = False + conn.set_autocommit(False) conn.commit() conn.rollback() with conn.transaction(): with pytest.raises(e.ProgrammingError): - conn.autocommit = False + conn.set_autocommit(False) with pytest.raises(e.ProgrammingError): conn.commit() with pytest.raises(e.ProgrammingError): conn.rollback() - conn.autocommit = False + conn.set_autocommit(False) conn.commit() conn.rollback() @@ -172,8 +171,7 @@ def test_preserves_autocommit(conn, autocommit): """ Connection.autocommit is unchanged both during and after Transaction block. """ - - conn.autocommit = autocommit + conn.set_autocommit(autocommit) with conn.transaction(): assert conn.autocommit is autocommit assert conn.autocommit is autocommit @@ -189,8 +187,7 @@ def test_autocommit_off_but_no_tx_started_successful_exit(conn, svcconn): Outcome: * Changes made within Transaction context are committed """ - - conn.autocommit = False + conn.set_autocommit(False) assert not in_transaction(conn) with conn.transaction(): insert_row(conn, "new") @@ -211,8 +208,7 @@ def test_autocommit_off_but_no_tx_started_exception_exit(conn, svcconn): Outcome: * Changes made within Transaction context are discarded """ - - conn.autocommit = False + conn.set_autocommit(False) assert not in_transaction(conn) with pytest.raises(ExpectedException): with conn.transaction(): @@ -238,8 +234,7 @@ def test_autocommit_off_and_tx_in_progress_successful_exit(conn, pipeline, svcco * Outer transaction is left running, and no changes are visible to an outside observer from another connection. """ - - conn.autocommit = False + conn.set_autocommit(False) insert_row(conn, "prior") if pipeline: pipeline.sync() @@ -266,8 +261,7 @@ def test_autocommit_off_and_tx_in_progress_exception_exit(conn, pipeline, svccon * Outer transaction is left running, and no changes are visible to an outside observer from another connection. """ - - conn.autocommit = False + conn.set_autocommit(False) insert_row(conn, "prior") if pipeline: pipeline.sync() @@ -645,7 +639,7 @@ def test_str(conn, pipeline): @pytest.mark.parametrize("exit_error", [None, ZeroDivisionError, Rollback]) def test_out_of_order_exit(conn, exit_error): - conn.autocommit = True + conn.set_autocommit(True) t1 = conn.transaction() t1.__enter__() @@ -679,7 +673,7 @@ def test_out_of_order_implicit_begin(conn, exit_error): @pytest.mark.parametrize("exit_error", [None, ZeroDivisionError, Rollback]) def test_out_of_order_exit_same_name(conn, exit_error): - conn.autocommit = True + conn.set_autocommit(True) t1 = conn.transaction("save") t1.__enter__() diff --git a/tools/async_to_sync.py b/tools/async_to_sync.py index 3375656fc..080267e57 100755 --- a/tools/async_to_sync.py +++ b/tools/async_to_sync.py @@ -34,7 +34,6 @@ def async_to_sync(tree: ast.AST) -> ast.AST: tree = BlanksInserter().visit(tree) tree = RenameAsyncToSync().visit(tree) tree = AsyncToSync().visit(tree) - tree = FixAsyncSetters().visit(tree) return tree @@ -128,7 +127,6 @@ class RenameAsyncToSync(ast.NodeTransformer): "acommands": "commands", "aconn": "conn", "aconn_cls": "conn_cls", - "aconn_set": "conn_set", "alist": "list", "anext": "next", "apipeline": "pipeline", @@ -243,37 +241,6 @@ class RenameAsyncToSync(ast.NodeTransformer): return node -class FixAsyncSetters(ast.NodeTransformer): - setters_map = { - "set_autocommit": "autocommit", - "set_read_only": "read_only", - "set_isolation_level": "isolation_level", - "set_deferrable": "deferrable", - } - - def visit_Call(self, node: ast.Call) -> ast.AST: - new_node = self._fix_setter(node) - if new_node: - return new_node - - self.generic_visit(node) - return node - - def _fix_setter(self, node: ast.Call) -> ast.AST | None: - if not isinstance(node.func, ast.Attribute): - return None - if node.func.attr not in self.setters_map: - return None - obj = node.func.value - arg = node.args[0] - new_node = ast.Assign( - targets=[ast.Attribute(value=obj, attr=self.setters_map[node.func.attr])], - value=arg, - ) - ast.copy_location(new_node, node) - return new_node - - class BlanksInserter(ast.NodeTransformer): """ Restore the missing spaces in the source (or something similar)