Skip to content

Commit 67d0f71

Browse files
committed
fix: allow setting connection.read_only to same value (#1247)
Setting the read_only value of a connection to the same value as the current value should be allowed during a transaction, as it does not change anything. SQLAlchemy regularly does this if engine options have been specified. Fixes googleapis/python-spanner-sqlalchemy#493
1 parent eeb7836 commit 67d0f71

File tree

3 files changed

+29
-1
lines changed

3 files changed

+29
-1
lines changed

google/cloud/spanner_dbapi/connection.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ def read_only(self, value):
239239
Args:
240240
value (bool): True for ReadOnly mode, False for ReadWrite.
241241
"""
242-
if self._spanner_transaction_started:
242+
if self._read_only != value and self._spanner_transaction_started:
243243
raise ValueError(
244244
"Connection read/write mode can't be changed while a transaction is in progress. "
245245
"Commit or rollback the current transaction and try again."

google/cloud/spanner_v1/database.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
from google.cloud.spanner_v1 import TransactionSelector
4848
from google.cloud.spanner_v1 import TransactionOptions
4949
from google.cloud.spanner_v1 import RequestOptions
50+
from google.cloud.spanner_v1 import SpannerAsyncClient
5051
from google.cloud.spanner_v1 import SpannerClient
5152
from google.cloud.spanner_v1._helpers import _merge_query_options
5253
from google.cloud.spanner_v1._helpers import (
@@ -143,6 +144,7 @@ class Database(object):
143144
"""
144145

145146
_spanner_api = None
147+
_spanner_async_api: SpannerAsyncClient = None
146148

147149
def __init__(
148150
self,
@@ -438,6 +440,28 @@ def spanner_api(self):
438440
)
439441
return self._spanner_api
440442

443+
@property
444+
def spanner_async_api(self):
445+
if self._spanner_async_api is None:
446+
client_info = self._instance._client._client_info
447+
client_options = self._instance._client._client_options
448+
if self._instance.emulator_host is not None:
449+
channel = grpc.aio.insecure_channel(target=self._instance.emulator_host)
450+
transport = SpannerGrpcTransport(channel=channel)
451+
self._spanner_async_api = SpannerAsyncClient(
452+
client_info=client_info, transport=transport
453+
)
454+
return self._spanner_async_api
455+
credentials = self._instance._client.credentials
456+
if isinstance(credentials, google.auth.credentials.Scoped):
457+
credentials = credentials.with_scopes((SPANNER_DATA_SCOPE,))
458+
self._spanner_async_api = SpannerAsyncClient(
459+
credentials=credentials,
460+
client_info=client_info,
461+
client_options=client_options,
462+
)
463+
return self._spanner_async_api
464+
441465
def __eq__(self, other):
442466
if not isinstance(other, self.__class__):
443467
return NotImplemented

tests/unit/spanner_dbapi/test_connection.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ def test_read_only_connection(self):
138138
):
139139
connection.read_only = False
140140

141+
# Verify that we can set the value to the same value as it already has.
142+
connection.read_only = True
143+
self.assertTrue(connection.read_only)
144+
141145
connection._spanner_transaction_started = False
142146
connection.read_only = False
143147
self.assertFalse(connection.read_only)

0 commit comments

Comments
 (0)