From 9fe89fbb3440c9b976f5a132e5982ed51c1e2a15 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 15 Apr 2026 09:48:14 -0400 Subject: [PATCH 1/3] test(spanner): disable pooling in mock server tests --- .../tests/mockserver_tests/mock_server_test_base.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/sqlalchemy-spanner/tests/mockserver_tests/mock_server_test_base.py b/packages/sqlalchemy-spanner/tests/mockserver_tests/mock_server_test_base.py index e44e9c8c841c..afafd0e93862 100644 --- a/packages/sqlalchemy-spanner/tests/mockserver_tests/mock_server_test_base.py +++ b/packages/sqlalchemy-spanner/tests/mockserver_tests/mock_server_test_base.py @@ -161,9 +161,12 @@ def teardown_method(self): MockServerTestBase.database_admin_service.clear_requests() def create_engine(self) -> Engine: + from sqlalchemy.pool import NullPool + return create_engine( "spanner:///projects/p/instances/i/databases/d", connect_args={"client": self.client, "logger": MockServerTestBase.logger}, + poolclass=NullPool, # Disable pooling to force new sessions for every test ) @property From bb6349fd7f82fe2f185db0cb91c02b25bbdc3ae1 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 15 Apr 2026 09:55:13 -0400 Subject: [PATCH 2/3] test(spanner): update mock server tests for inlined transactions --- .../mockserver_tests/mock_server_test_base.py | 3 --- .../mockserver_tests/test_auto_increment.py | 11 +++++----- .../test_bit_reversed_sequence.py | 11 +++++----- .../tests/mockserver_tests/test_float32.py | 12 ++++++----- .../tests/mockserver_tests/test_insertmany.py | 20 ++++++++++--------- .../mockserver_tests/test_isolation_level.py | 12 +++++------ .../tests/mockserver_tests/test_json.py | 13 ++++++------ .../mockserver_tests/test_pickle_type.py | 13 ++++++------ .../tests/mockserver_tests/test_quickstart.py | 14 ++++++------- .../tests/mockserver_tests/test_tags.py | 16 +++++++-------- 10 files changed, 65 insertions(+), 60 deletions(-) diff --git a/packages/sqlalchemy-spanner/tests/mockserver_tests/mock_server_test_base.py b/packages/sqlalchemy-spanner/tests/mockserver_tests/mock_server_test_base.py index afafd0e93862..e44e9c8c841c 100644 --- a/packages/sqlalchemy-spanner/tests/mockserver_tests/mock_server_test_base.py +++ b/packages/sqlalchemy-spanner/tests/mockserver_tests/mock_server_test_base.py @@ -161,12 +161,9 @@ def teardown_method(self): MockServerTestBase.database_admin_service.clear_requests() def create_engine(self) -> Engine: - from sqlalchemy.pool import NullPool - return create_engine( "spanner:///projects/p/instances/i/databases/d", connect_args={"client": self.client, "logger": MockServerTestBase.logger}, - poolclass=NullPool, # Disable pooling to force new sessions for every test ) @property diff --git a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_auto_increment.py b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_auto_increment.py index d0232a78a5ac..adb2f7d7551f 100644 --- a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_auto_increment.py +++ b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_auto_increment.py @@ -13,7 +13,7 @@ # limitations under the License. from sqlalchemy.orm import Session -from sqlalchemy.testing import eq_, is_instance_of +from sqlalchemy.testing import eq_, is_instance_of, is_not_none from google.cloud.spanner_v1 import ( ResultSet, CreateSessionRequest, @@ -126,11 +126,12 @@ def test_insert_row(self): session.commit() # Verify the requests that we got. requests = self.spanner_service.requests - eq_(4, len(requests)) + # Dialect now inlines BeginTransaction into the first statement. + eq_(3, len(requests)) is_instance_of(requests[0], CreateSessionRequest) - is_instance_of(requests[1], BeginTransactionRequest) - is_instance_of(requests[2], ExecuteSqlRequest) - is_instance_of(requests[3], CommitRequest) + is_instance_of(requests[1], ExecuteSqlRequest) + is_instance_of(requests[2], CommitRequest) + is_not_none(requests[1].transaction.begin) # First request inlines begin def test_insert_row_with_pk_value(self): from tests.mockserver_tests.auto_increment_model import Singer diff --git a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_bit_reversed_sequence.py b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_bit_reversed_sequence.py index 53357eb9cad3..92fce2a3293a 100644 --- a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_bit_reversed_sequence.py +++ b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_bit_reversed_sequence.py @@ -13,7 +13,7 @@ # limitations under the License. from sqlalchemy.orm import Session -from sqlalchemy.testing import eq_, is_instance_of +from sqlalchemy.testing import eq_, is_instance_of, is_not_none from google.cloud.spanner_v1 import ( ResultSet, CreateSessionRequest, @@ -119,8 +119,9 @@ def test_insert_row(self): session.commit() # Verify the requests that we got. requests = self.spanner_service.requests - eq_(4, len(requests)) + # Dialect now inlines BeginTransaction into the first statement. + eq_(3, len(requests)) is_instance_of(requests[0], CreateSessionRequest) - is_instance_of(requests[1], BeginTransactionRequest) - is_instance_of(requests[2], ExecuteSqlRequest) - is_instance_of(requests[3], CommitRequest) + is_instance_of(requests[1], ExecuteSqlRequest) + is_instance_of(requests[2], CommitRequest) + is_not_none(requests[1].transaction.begin) # First request inlines begin diff --git a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_float32.py b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_float32.py index 47f03ff30865..51e125b8f621 100644 --- a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_float32.py +++ b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_float32.py @@ -17,6 +17,7 @@ eq_, is_instance_of, is_false, + is_not_none, ) from google.cloud.spanner_v1 import ( CreateSessionRequest, @@ -58,12 +59,13 @@ def test_insert_data(self): session.commit() requests = self.spanner_service.requests - eq_(4, len(requests)) + # Dialect now inlines BeginTransaction into the first statement. + eq_(3, len(requests)) is_instance_of(requests[0], CreateSessionRequest) - is_instance_of(requests[1], BeginTransactionRequest) - is_instance_of(requests[2], ExecuteSqlRequest) - is_instance_of(requests[3], CommitRequest) - request: ExecuteSqlRequest = requests[2] + is_instance_of(requests[1], ExecuteSqlRequest) + is_instance_of(requests[2], CommitRequest) + is_not_none(requests[1].transaction.begin) # First request inlines begin + request: ExecuteSqlRequest = requests[1] eq_(3, len(request.params)) eq_("1", request.params["a0"]) eq_("One", request.params["a1"]) diff --git a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_insertmany.py b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_insertmany.py index 39626026dccc..345594e6f1f9 100644 --- a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_insertmany.py +++ b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_insertmany.py @@ -17,7 +17,7 @@ import sqlalchemy from sqlalchemy.orm import Session -from sqlalchemy.testing import eq_, is_instance_of +from sqlalchemy.testing import eq_, is_instance_of, is_not_none from google.cloud.spanner_v1 import ( ExecuteSqlRequest, CommitRequest, @@ -53,11 +53,12 @@ def test_insertmany_with_uuid_sentinels(self): # Verify the requests that we got. requests = self.spanner_service.requests - eq_(4, len(requests)) + # Dialect now inlines BeginTransaction into the first statement. + eq_(3, len(requests)) is_instance_of(requests[0], CreateSessionRequest) - is_instance_of(requests[1], BeginTransactionRequest) - is_instance_of(requests[2], ExecuteSqlRequest) - is_instance_of(requests[3], CommitRequest) + is_instance_of(requests[1], ExecuteSqlRequest) + is_instance_of(requests[2], CommitRequest) + is_not_none(requests[1].transaction.begin) # First request inlines begin def test_no_insertmany_with_bit_reversed_id(self): """Ensures we don't try to bulk insert rows with bit-reversed PKs. @@ -93,12 +94,13 @@ def test_no_insertmany_with_bit_reversed_id(self): # Verify the requests that we got. requests = self.spanner_service.requests - eq_(5, len(requests)) + # Dialect now inlines BeginTransaction into the first statement. + eq_(4, len(requests)) is_instance_of(requests[0], CreateSessionRequest) - is_instance_of(requests[1], BeginTransactionRequest) + is_instance_of(requests[1], ExecuteSqlRequest) is_instance_of(requests[2], ExecuteSqlRequest) - is_instance_of(requests[3], ExecuteSqlRequest) - is_instance_of(requests[4], RollbackRequest) + is_instance_of(requests[3], RollbackRequest) + is_not_none(requests[1].transaction.begin) # First request inlines begin def add_uuid_insert_result(self, sql): result = result_set.ResultSet( diff --git a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_isolation_level.py b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_isolation_level.py index 440e6cb0d0f2..c7119f28ffcf 100644 --- a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_isolation_level.py +++ b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_isolation_level.py @@ -150,12 +150,12 @@ def test_invalid_isolation_level(self): def verify_isolation_level(self, level): # Verify the requests that we got. requests = self.spanner_service.requests - eq_(4, len(requests)) + # Dialect now inlines BeginTransaction into the first statement. + eq_(3, len(requests)) is_instance_of(requests[0], CreateSessionRequest) - is_instance_of(requests[1], BeginTransactionRequest) - is_instance_of(requests[2], ExecuteSqlRequest) - is_instance_of(requests[3], CommitRequest) - begin_request: BeginTransactionRequest = requests[1] + is_instance_of(requests[1], ExecuteSqlRequest) + is_instance_of(requests[2], CommitRequest) + execute_request: ExecuteSqlRequest = requests[1] eq_( TransactionOptions( dict( @@ -163,7 +163,7 @@ def verify_isolation_level(self, level): read_write=TransactionOptions.ReadWrite(), ) ), - begin_request.options, + execute_request.transaction.begin, ) def add_insert_result(self, sql): diff --git a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_json.py b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_json.py index 9b4606b858df..dc2ea027ee57 100644 --- a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_json.py +++ b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_json.py @@ -14,7 +14,7 @@ from sqlalchemy import func, select, text from sqlalchemy.orm import Session -from sqlalchemy.testing import eq_, is_instance_of +from sqlalchemy.testing import eq_, is_instance_of, is_not_none from google.cloud.spanner_v1 import ( ResultSet, CreateSessionRequest, @@ -105,12 +105,13 @@ def _test_insert_json( # Verify the requests that we got. requests = self.spanner_service.requests - eq_(4, len(requests)) + # Dialect now inlines BeginTransaction into the first statement. + eq_(3, len(requests)) is_instance_of(requests[0], CreateSessionRequest) - is_instance_of(requests[1], BeginTransactionRequest) - is_instance_of(requests[2], ExecuteSqlRequest) - is_instance_of(requests[3], CommitRequest) - request: ExecuteSqlRequest = requests[2] + is_instance_of(requests[1], ExecuteSqlRequest) + is_instance_of(requests[2], CommitRequest) + is_not_none(requests[1].transaction.begin) # First request inlines begin + request: ExecuteSqlRequest = requests[1] eq_(3, len(request.params)) eq_("1", request.params["a0"]) eq_("Test", request.params["a1"]) diff --git a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_pickle_type.py b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_pickle_type.py index e5d6c4bee81d..15cc4446d1ed 100644 --- a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_pickle_type.py +++ b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_pickle_type.py @@ -13,7 +13,7 @@ # limitations under the License. from sqlalchemy.orm import Session -from sqlalchemy.testing import eq_, is_instance_of +from sqlalchemy.testing import eq_, is_instance_of, is_not_none from google.cloud.spanner_v1 import ( ResultSet, CreateSessionRequest, @@ -85,12 +85,13 @@ def test_insert_and_query(self): # Verify the requests that we got. requests = self.spanner_service.requests - eq_(4, len(requests)) + # Dialect now inlines BeginTransaction into the first statement. + eq_(3, len(requests)) is_instance_of(requests[0], CreateSessionRequest) - is_instance_of(requests[1], BeginTransactionRequest) - is_instance_of(requests[2], ExecuteSqlRequest) - is_instance_of(requests[3], CommitRequest) - request: ExecuteSqlRequest = requests[2] + is_instance_of(requests[1], ExecuteSqlRequest) + is_instance_of(requests[2], CommitRequest) + is_not_none(requests[1].transaction.begin) # First request inlines begin + request: ExecuteSqlRequest = requests[1] eq_(4, len(request.params)) eq_("1", request.params["a0"]) eq_("test_user", request.params["a1"]) diff --git a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_quickstart.py b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_quickstart.py index 35f6bd56d041..b41b756888e6 100644 --- a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_quickstart.py +++ b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_quickstart.py @@ -115,12 +115,12 @@ def test_insert_data(self): session.commit() requests = self.spanner_service.requests - eq_(5, len(requests)) + # Dialect now inlines BeginTransaction into the first statement. + eq_(4, len(requests)) is_instance_of(requests[0], CreateSessionRequest) - is_instance_of(requests[1], BeginTransactionRequest) + is_instance_of(requests[1], ExecuteBatchDmlRequest) is_instance_of(requests[2], ExecuteBatchDmlRequest) - is_instance_of(requests[3], ExecuteBatchDmlRequest) - is_instance_of(requests[4], CommitRequest) - is_not_none(requests[2].transaction.id) - eq_(requests[2].transaction.id, requests[3].transaction.id) - eq_(requests[2].transaction.id, requests[4].transaction_id) + is_instance_of(requests[3], CommitRequest) + is_not_none(requests[1].transaction.begin) # First request inlines begin + is_not_none(requests[2].transaction.id) # Subsequent requests use ID + eq_(requests[2].transaction.id, requests[3].transaction_id) diff --git a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_tags.py b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_tags.py index a1fc51ae6417..f391b3737b2d 100644 --- a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_tags.py +++ b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_tags.py @@ -83,18 +83,18 @@ def test_transaction_tag(self): # Verify the requests that we got. requests = self.spanner_service.requests - eq_(6, len(requests)) + # Dialect now inlines BeginTransaction into the first statement. + eq_(5, len(requests)) is_instance_of(requests[0], CreateSessionRequest) - is_instance_of(requests[1], BeginTransactionRequest) + is_instance_of(requests[1], ExecuteSqlRequest) is_instance_of(requests[2], ExecuteSqlRequest) is_instance_of(requests[3], ExecuteSqlRequest) - is_instance_of(requests[4], ExecuteSqlRequest) - is_instance_of(requests[5], CommitRequest) - for request in requests[2:]: + is_instance_of(requests[4], CommitRequest) + for request in requests[1:]: eq_("my-transaction-tag", request.request_options.transaction_tag) - eq_("my-tag-1", requests[2].request_options.request_tag) - eq_("my-tag-2", requests[3].request_options.request_tag) - eq_("insert-singer", requests[4].request_options.request_tag) + eq_("my-tag-1", requests[1].request_options.request_tag) + eq_("my-tag-2", requests[2].request_options.request_tag) + eq_("insert-singer", requests[3].request_options.request_tag) def empty_singer_result_set(): From f28306231c4f4f18a92dac6add8bae70e4e28e98 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 15 Apr 2026 09:59:23 -0400 Subject: [PATCH 3/3] style(spanner): remove unused BeginTransactionRequest imports --- .../tests/mockserver_tests/test_auto_increment.py | 1 - .../tests/mockserver_tests/test_bit_reversed_sequence.py | 1 - .../sqlalchemy-spanner/tests/mockserver_tests/test_float32.py | 1 - .../sqlalchemy-spanner/tests/mockserver_tests/test_insertmany.py | 1 - .../tests/mockserver_tests/test_isolation_level.py | 1 - packages/sqlalchemy-spanner/tests/mockserver_tests/test_json.py | 1 - .../tests/mockserver_tests/test_pickle_type.py | 1 - .../sqlalchemy-spanner/tests/mockserver_tests/test_quickstart.py | 1 - 8 files changed, 8 deletions(-) diff --git a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_auto_increment.py b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_auto_increment.py index adb2f7d7551f..5cfd83c02b27 100644 --- a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_auto_increment.py +++ b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_auto_increment.py @@ -19,7 +19,6 @@ CreateSessionRequest, ExecuteSqlRequest, CommitRequest, - BeginTransactionRequest, ) from tests.mockserver_tests.mock_server_test_base import ( MockServerTestBase, diff --git a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_bit_reversed_sequence.py b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_bit_reversed_sequence.py index 92fce2a3293a..429d961f6575 100644 --- a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_bit_reversed_sequence.py +++ b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_bit_reversed_sequence.py @@ -19,7 +19,6 @@ CreateSessionRequest, ExecuteSqlRequest, CommitRequest, - BeginTransactionRequest, ) from tests.mockserver_tests.mock_server_test_base import ( MockServerTestBase, diff --git a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_float32.py b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_float32.py index 51e125b8f621..dde2d4cffa30 100644 --- a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_float32.py +++ b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_float32.py @@ -24,7 +24,6 @@ ExecuteSqlRequest, ResultSet, ResultSetStats, - BeginTransactionRequest, CommitRequest, TypeCode, ) diff --git a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_insertmany.py b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_insertmany.py index 345594e6f1f9..ad2db5118bc1 100644 --- a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_insertmany.py +++ b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_insertmany.py @@ -22,7 +22,6 @@ ExecuteSqlRequest, CommitRequest, RollbackRequest, - BeginTransactionRequest, CreateSessionRequest, ) from tests.mockserver_tests.mock_server_test_base import ( diff --git a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_isolation_level.py b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_isolation_level.py index c7119f28ffcf..b08f86b7c377 100644 --- a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_isolation_level.py +++ b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_isolation_level.py @@ -19,7 +19,6 @@ CreateSessionRequest, ExecuteSqlRequest, CommitRequest, - BeginTransactionRequest, TransactionOptions, ) diff --git a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_json.py b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_json.py index dc2ea027ee57..f85b139b74a1 100644 --- a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_json.py +++ b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_json.py @@ -20,7 +20,6 @@ CreateSessionRequest, ExecuteSqlRequest, CommitRequest, - BeginTransactionRequest, TypeCode, JsonObject, ) diff --git a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_pickle_type.py b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_pickle_type.py index 15cc4446d1ed..026f362cbc16 100644 --- a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_pickle_type.py +++ b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_pickle_type.py @@ -19,7 +19,6 @@ CreateSessionRequest, ExecuteSqlRequest, CommitRequest, - BeginTransactionRequest, TypeCode, ) from tests.mockserver_tests.mock_server_test_base import ( diff --git a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_quickstart.py b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_quickstart.py index b41b756888e6..a7d06fdeebaa 100644 --- a/packages/sqlalchemy-spanner/tests/mockserver_tests/test_quickstart.py +++ b/packages/sqlalchemy-spanner/tests/mockserver_tests/test_quickstart.py @@ -19,7 +19,6 @@ CreateSessionRequest, ExecuteBatchDmlRequest, CommitRequest, - BeginTransactionRequest, ) from sqlalchemy.orm import Session from sqlalchemy.testing import eq_, is_instance_of, is_not_none