from psycopg3 import ProgrammingError, Rollback
from psycopg3.sql import Composable
+from psycopg3.transaction import Transaction
@pytest.fixture(autouse=True)
invalid SQL command and having that fail with an OperationalError).
"""
with pytest.raises(ValueError):
- conn.transaction(savepoint_name="")
+ with conn.transaction(savepoint_name=""):
+ pass
def test_named_savepoint_escapes_savepoint_name(conn):
...and exiting the context successfully will "commit" the same.
"""
# Case 1
- tx = conn.transaction()
+ # Using Transaction explicitly becase conn.transaction() enters the contetx
+ tx = Transaction(conn)
with assert_commands_issued(conn, "begin"):
tx.__enter__()
assert tx.savepoint_name is None
tx.__exit__(None, None, None)
# Case 2
- tx = conn.transaction(savepoint_name="foo")
+ tx = Transaction(conn, savepoint_name="foo")
with assert_commands_issued(conn, "begin", 'savepoint "foo"'):
tx.__enter__()
assert tx.savepoint_name == "foo"
tx.__exit__(None, None, None)
# Case 3 (with savepoint name provided)
- with conn.transaction():
- tx = conn.transaction(savepoint_name="bar")
+ with Transaction(conn):
+ tx = Transaction(conn, savepoint_name="bar")
with assert_commands_issued(conn, 'savepoint "bar"'):
tx.__enter__()
assert tx.savepoint_name == "bar"
# Case 3 (with savepoint name auto-generated)
with conn.transaction():
- tx = conn.transaction()
+ tx = Transaction(conn)
with assert_commands_issued(conn, 'savepoint "s1"'):
tx.__enter__()
assert tx.savepoint_name == "s1"
be rolled-back as appropriate.
"""
# Case 1
- tx = conn.transaction()
+ tx = Transaction(conn)
with assert_commands_issued(conn, "begin"):
tx.__enter__()
assert tx.savepoint_name is None
tx.__exit__(*some_exc_info())
# Case 2
- tx = conn.transaction(savepoint_name="foo")
+ tx = Transaction(conn, savepoint_name="foo")
with assert_commands_issued(conn, "begin", 'savepoint "foo"'):
tx.__enter__()
assert tx.savepoint_name == "foo"
# Case 3 (with savepoint name provided)
with conn.transaction():
- tx = conn.transaction(savepoint_name="bar")
+ tx = Transaction(conn, savepoint_name="bar")
with assert_commands_issued(conn, 'savepoint "bar"'):
tx.__enter__()
assert tx.savepoint_name == "bar"
# Case 3 (with savepoint name auto-generated)
with conn.transaction():
- tx = conn.transaction()
+ tx = Transaction(conn)
with assert_commands_issued(conn, 'savepoint "s1"'):
tx.__enter__()
assert tx.savepoint_name == "s1"
- Rollback(tx) (instance initialised with reference to the transaction)
All of these are equivalent.
"""
- tx = conn.transaction()
- for to_raise in (
- Rollback,
- Rollback(),
- Rollback(tx),
- ):
- with tx:
- insert_row(conn, "foo")
- raise to_raise
- assert_rows(conn, set(""))
+
+ def assert_no_rows():
+ assert_rows(conn, set())
assert_rows(svcconn, set())
+ with conn.transaction():
+ insert_row(conn, "foo")
+ raise Rollback
+ assert_no_rows()
+
+ with conn.transaction():
+ insert_row(conn, "foo")
+ raise Rollback()
+ assert_no_rows()
+
+ with conn.transaction() as tx:
+ insert_row(conn, "foo")
+ raise Rollback(tx)
+ assert_no_rows()
+
def test_explicit_rollback_outer_tx_unaffected(conn, svcconn):
"""
Raising a Rollback exception that references an outer transaction will
discard all changes from both inner and outer transaction blocks.
"""
- outer_tx = conn.transaction()
- with outer_tx:
+ with conn.transaction() as outer_tx:
insert_row(conn, "outer")
with conn.transaction():
insert_row(conn, "inner")
provide a helpful error message if they call __exit__() in the wrong order
for nested transactions.
"""
- tx1, tx2 = conn.transaction(name), conn.transaction()
+ tx1, tx2 = Transaction(conn, name), Transaction(conn)
tx1.__enter__()
tx2.__enter__()
with pytest.raises(ProgrammingError, match="Out-of-order"):
provide a helpful error message if they call __exit__() without first
having called __enter__()
"""
- tx = conn.transaction(name)
+ tx = Transaction(conn, name)
with pytest.raises(ProgrammingError, match="Out-of-order"):
tx.__exit__(*exc_info)
When user is calling __enter__() and __exit__() manually for some reason,
provide a helpful error message if they accidentally call __exit__() twice.
"""
- tx = conn.transaction(name)
+ tx = Transaction(conn, name)
tx.__enter__()
tx.__exit__(*exc_info)
with pytest.raises(ProgrammingError, match="Out-of-order"):