google-cloud-spanner 3.55.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. google/cloud/spanner.py +47 -0
  2. google/cloud/spanner_admin_database_v1/__init__.py +146 -0
  3. google/cloud/spanner_admin_database_v1/gapic_metadata.json +418 -0
  4. google/cloud/spanner_admin_database_v1/gapic_version.py +16 -0
  5. google/cloud/spanner_admin_database_v1/py.typed +2 -0
  6. google/cloud/spanner_admin_database_v1/services/__init__.py +15 -0
  7. google/cloud/spanner_admin_database_v1/services/database_admin/__init__.py +22 -0
  8. google/cloud/spanner_admin_database_v1/services/database_admin/async_client.py +4097 -0
  9. google/cloud/spanner_admin_database_v1/services/database_admin/client.py +4602 -0
  10. google/cloud/spanner_admin_database_v1/services/database_admin/pagers.py +989 -0
  11. google/cloud/spanner_admin_database_v1/services/database_admin/transports/__init__.py +38 -0
  12. google/cloud/spanner_admin_database_v1/services/database_admin/transports/base.py +820 -0
  13. google/cloud/spanner_admin_database_v1/services/database_admin/transports/grpc.py +1303 -0
  14. google/cloud/spanner_admin_database_v1/services/database_admin/transports/grpc_asyncio.py +1688 -0
  15. google/cloud/spanner_admin_database_v1/services/database_admin/transports/rest.py +6512 -0
  16. google/cloud/spanner_admin_database_v1/services/database_admin/transports/rest_base.py +1650 -0
  17. google/cloud/spanner_admin_database_v1/types/__init__.py +144 -0
  18. google/cloud/spanner_admin_database_v1/types/backup.py +1106 -0
  19. google/cloud/spanner_admin_database_v1/types/backup_schedule.py +369 -0
  20. google/cloud/spanner_admin_database_v1/types/common.py +180 -0
  21. google/cloud/spanner_admin_database_v1/types/spanner_database_admin.py +1303 -0
  22. google/cloud/spanner_admin_instance_v1/__init__.py +110 -0
  23. google/cloud/spanner_admin_instance_v1/gapic_metadata.json +343 -0
  24. google/cloud/spanner_admin_instance_v1/gapic_version.py +16 -0
  25. google/cloud/spanner_admin_instance_v1/py.typed +2 -0
  26. google/cloud/spanner_admin_instance_v1/services/__init__.py +15 -0
  27. google/cloud/spanner_admin_instance_v1/services/instance_admin/__init__.py +22 -0
  28. google/cloud/spanner_admin_instance_v1/services/instance_admin/async_client.py +3466 -0
  29. google/cloud/spanner_admin_instance_v1/services/instance_admin/client.py +3881 -0
  30. google/cloud/spanner_admin_instance_v1/services/instance_admin/pagers.py +856 -0
  31. google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/__init__.py +38 -0
  32. google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/base.py +545 -0
  33. google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/grpc.py +1347 -0
  34. google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/grpc_asyncio.py +1539 -0
  35. google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/rest.py +4834 -0
  36. google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/rest_base.py +1198 -0
  37. google/cloud/spanner_admin_instance_v1/types/__init__.py +104 -0
  38. google/cloud/spanner_admin_instance_v1/types/common.py +99 -0
  39. google/cloud/spanner_admin_instance_v1/types/spanner_instance_admin.py +2375 -0
  40. google/cloud/spanner_dbapi/__init__.py +93 -0
  41. google/cloud/spanner_dbapi/_helpers.py +113 -0
  42. google/cloud/spanner_dbapi/batch_dml_executor.py +135 -0
  43. google/cloud/spanner_dbapi/checksum.py +80 -0
  44. google/cloud/spanner_dbapi/client_side_statement_executor.py +140 -0
  45. google/cloud/spanner_dbapi/client_side_statement_parser.py +106 -0
  46. google/cloud/spanner_dbapi/connection.py +818 -0
  47. google/cloud/spanner_dbapi/cursor.py +609 -0
  48. google/cloud/spanner_dbapi/exceptions.py +172 -0
  49. google/cloud/spanner_dbapi/parse_utils.py +392 -0
  50. google/cloud/spanner_dbapi/parsed_statement.py +63 -0
  51. google/cloud/spanner_dbapi/parser.py +258 -0
  52. google/cloud/spanner_dbapi/partition_helper.py +41 -0
  53. google/cloud/spanner_dbapi/transaction_helper.py +294 -0
  54. google/cloud/spanner_dbapi/types.py +106 -0
  55. google/cloud/spanner_dbapi/utils.py +147 -0
  56. google/cloud/spanner_dbapi/version.py +20 -0
  57. google/cloud/spanner_v1/__init__.py +154 -0
  58. google/cloud/spanner_v1/_helpers.py +751 -0
  59. google/cloud/spanner_v1/_opentelemetry_tracing.py +165 -0
  60. google/cloud/spanner_v1/backup.py +397 -0
  61. google/cloud/spanner_v1/batch.py +433 -0
  62. google/cloud/spanner_v1/client.py +538 -0
  63. google/cloud/spanner_v1/data_types.py +350 -0
  64. google/cloud/spanner_v1/database.py +1968 -0
  65. google/cloud/spanner_v1/database_sessions_manager.py +249 -0
  66. google/cloud/spanner_v1/gapic_metadata.json +268 -0
  67. google/cloud/spanner_v1/gapic_version.py +16 -0
  68. google/cloud/spanner_v1/instance.py +735 -0
  69. google/cloud/spanner_v1/keyset.py +193 -0
  70. google/cloud/spanner_v1/merged_result_set.py +146 -0
  71. google/cloud/spanner_v1/metrics/constants.py +71 -0
  72. google/cloud/spanner_v1/metrics/metrics_capture.py +75 -0
  73. google/cloud/spanner_v1/metrics/metrics_exporter.py +384 -0
  74. google/cloud/spanner_v1/metrics/metrics_interceptor.py +156 -0
  75. google/cloud/spanner_v1/metrics/metrics_tracer.py +588 -0
  76. google/cloud/spanner_v1/metrics/metrics_tracer_factory.py +328 -0
  77. google/cloud/spanner_v1/metrics/spanner_metrics_tracer_factory.py +172 -0
  78. google/cloud/spanner_v1/param_types.py +110 -0
  79. google/cloud/spanner_v1/pool.py +813 -0
  80. google/cloud/spanner_v1/py.typed +2 -0
  81. google/cloud/spanner_v1/request_id_header.py +64 -0
  82. google/cloud/spanner_v1/services/__init__.py +15 -0
  83. google/cloud/spanner_v1/services/spanner/__init__.py +22 -0
  84. google/cloud/spanner_v1/services/spanner/async_client.py +2205 -0
  85. google/cloud/spanner_v1/services/spanner/client.py +2624 -0
  86. google/cloud/spanner_v1/services/spanner/pagers.py +196 -0
  87. google/cloud/spanner_v1/services/spanner/transports/__init__.py +38 -0
  88. google/cloud/spanner_v1/services/spanner/transports/base.py +520 -0
  89. google/cloud/spanner_v1/services/spanner/transports/grpc.py +911 -0
  90. google/cloud/spanner_v1/services/spanner/transports/grpc_asyncio.py +1144 -0
  91. google/cloud/spanner_v1/services/spanner/transports/rest.py +3468 -0
  92. google/cloud/spanner_v1/services/spanner/transports/rest_base.py +981 -0
  93. google/cloud/spanner_v1/session.py +631 -0
  94. google/cloud/spanner_v1/session_options.py +133 -0
  95. google/cloud/spanner_v1/snapshot.py +1057 -0
  96. google/cloud/spanner_v1/streamed.py +402 -0
  97. google/cloud/spanner_v1/table.py +181 -0
  98. google/cloud/spanner_v1/testing/__init__.py +0 -0
  99. google/cloud/spanner_v1/testing/database_test.py +121 -0
  100. google/cloud/spanner_v1/testing/interceptors.py +118 -0
  101. google/cloud/spanner_v1/testing/mock_database_admin.py +38 -0
  102. google/cloud/spanner_v1/testing/mock_spanner.py +261 -0
  103. google/cloud/spanner_v1/testing/spanner_database_admin_pb2_grpc.py +1267 -0
  104. google/cloud/spanner_v1/testing/spanner_pb2_grpc.py +882 -0
  105. google/cloud/spanner_v1/transaction.py +747 -0
  106. google/cloud/spanner_v1/types/__init__.py +118 -0
  107. google/cloud/spanner_v1/types/commit_response.py +94 -0
  108. google/cloud/spanner_v1/types/keys.py +248 -0
  109. google/cloud/spanner_v1/types/mutation.py +201 -0
  110. google/cloud/spanner_v1/types/query_plan.py +220 -0
  111. google/cloud/spanner_v1/types/result_set.py +379 -0
  112. google/cloud/spanner_v1/types/spanner.py +1815 -0
  113. google/cloud/spanner_v1/types/transaction.py +818 -0
  114. google/cloud/spanner_v1/types/type.py +288 -0
  115. google_cloud_spanner-3.55.0.dist-info/LICENSE +202 -0
  116. google_cloud_spanner-3.55.0.dist-info/METADATA +318 -0
  117. google_cloud_spanner-3.55.0.dist-info/RECORD +119 -0
  118. google_cloud_spanner-3.55.0.dist-info/WHEEL +5 -0
  119. google_cloud_spanner-3.55.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,433 @@
1
+ # Copyright 2016 Google LLC All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Context manager for Cloud Spanner batched writes."""
16
+ import functools
17
+
18
+ from google.cloud.spanner_v1 import CommitRequest
19
+ from google.cloud.spanner_v1 import Mutation
20
+ from google.cloud.spanner_v1 import TransactionOptions
21
+ from google.cloud.spanner_v1 import BatchWriteRequest
22
+
23
+ from google.cloud.spanner_v1._helpers import _SessionWrapper
24
+ from google.cloud.spanner_v1._helpers import _make_list_value_pbs
25
+ from google.cloud.spanner_v1._helpers import (
26
+ _metadata_with_prefix,
27
+ _metadata_with_leader_aware_routing,
28
+ _merge_Transaction_Options,
29
+ AtomicCounter,
30
+ )
31
+ from google.cloud.spanner_v1._opentelemetry_tracing import trace_call
32
+ from google.cloud.spanner_v1 import RequestOptions
33
+ from google.cloud.spanner_v1._helpers import _retry
34
+ from google.cloud.spanner_v1._helpers import _retry_on_aborted_exception
35
+ from google.cloud.spanner_v1._helpers import _check_rst_stream_error
36
+ from google.api_core.exceptions import InternalServerError
37
+ from google.cloud.spanner_v1.metrics.metrics_capture import MetricsCapture
38
+ import time
39
+
40
+ DEFAULT_RETRY_TIMEOUT_SECS = 30
41
+
42
+
43
+ class _BatchBase(_SessionWrapper):
44
+ """Accumulate mutations for transmission during :meth:`commit`.
45
+
46
+ :type session: :class:`~google.cloud.spanner_v1.session.Session`
47
+ :param session: the session used to perform the commit
48
+ """
49
+
50
+ transaction_tag = None
51
+ _read_only = False
52
+
53
+ def __init__(self, session):
54
+ super(_BatchBase, self).__init__(session)
55
+ self._mutations = []
56
+
57
+ def _check_state(self):
58
+ """Helper for :meth:`commit` et al.
59
+
60
+ Subclasses must override
61
+
62
+ :raises: :exc:`ValueError` if the object's state is invalid for making
63
+ API requests.
64
+ """
65
+ raise NotImplementedError
66
+
67
+ def insert(self, table, columns, values):
68
+ """Insert one or more new table rows.
69
+
70
+ :type table: str
71
+ :param table: Name of the table to be modified.
72
+
73
+ :type columns: list of str
74
+ :param columns: Name of the table columns to be modified.
75
+
76
+ :type values: list of lists
77
+ :param values: Values to be modified.
78
+ """
79
+ self._mutations.append(Mutation(insert=_make_write_pb(table, columns, values)))
80
+ # TODO: Decide if we should add a span event per mutation:
81
+ # https://github.com/googleapis/python-spanner/issues/1269
82
+
83
+ def update(self, table, columns, values):
84
+ """Update one or more existing table rows.
85
+
86
+ :type table: str
87
+ :param table: Name of the table to be modified.
88
+
89
+ :type columns: list of str
90
+ :param columns: Name of the table columns to be modified.
91
+
92
+ :type values: list of lists
93
+ :param values: Values to be modified.
94
+ """
95
+ self._mutations.append(Mutation(update=_make_write_pb(table, columns, values)))
96
+ # TODO: Decide if we should add a span event per mutation:
97
+ # https://github.com/googleapis/python-spanner/issues/1269
98
+
99
+ def insert_or_update(self, table, columns, values):
100
+ """Insert/update one or more table rows.
101
+
102
+ :type table: str
103
+ :param table: Name of the table to be modified.
104
+
105
+ :type columns: list of str
106
+ :param columns: Name of the table columns to be modified.
107
+
108
+ :type values: list of lists
109
+ :param values: Values to be modified.
110
+ """
111
+ self._mutations.append(
112
+ Mutation(insert_or_update=_make_write_pb(table, columns, values))
113
+ )
114
+ # TODO: Decide if we should add a span event per mutation:
115
+ # https://github.com/googleapis/python-spanner/issues/1269
116
+
117
+ def replace(self, table, columns, values):
118
+ """Replace one or more table rows.
119
+
120
+ :type table: str
121
+ :param table: Name of the table to be modified.
122
+
123
+ :type columns: list of str
124
+ :param columns: Name of the table columns to be modified.
125
+
126
+ :type values: list of lists
127
+ :param values: Values to be modified.
128
+ """
129
+ self._mutations.append(Mutation(replace=_make_write_pb(table, columns, values)))
130
+ # TODO: Decide if we should add a span event per mutation:
131
+ # https://github.com/googleapis/python-spanner/issues/1269
132
+
133
+ def delete(self, table, keyset):
134
+ """Delete one or more table rows.
135
+
136
+ :type table: str
137
+ :param table: Name of the table to be modified.
138
+
139
+ :type keyset: :class:`~google.cloud.spanner_v1.keyset.Keyset`
140
+ :param keyset: Keys/ranges identifying rows to delete.
141
+ """
142
+ delete = Mutation.Delete(table=table, key_set=keyset._to_pb())
143
+ self._mutations.append(Mutation(delete=delete))
144
+ # TODO: Decide if we should add a span event per mutation:
145
+ # https://github.com/googleapis/python-spanner/issues/1269
146
+
147
+
148
+ class Batch(_BatchBase):
149
+ """Accumulate mutations for transmission during :meth:`commit`."""
150
+
151
+ committed = None
152
+ commit_stats = None
153
+ """Timestamp at which the batch was successfully committed."""
154
+
155
+ def _check_state(self):
156
+ """Helper for :meth:`commit` et al.
157
+
158
+ Subclasses must override
159
+
160
+ :raises: :exc:`ValueError` if the object's state is invalid for making
161
+ API requests.
162
+ """
163
+ if self.committed is not None:
164
+ raise ValueError("Batch already committed")
165
+
166
+ def commit(
167
+ self,
168
+ return_commit_stats=False,
169
+ request_options=None,
170
+ max_commit_delay=None,
171
+ exclude_txn_from_change_streams=False,
172
+ isolation_level=TransactionOptions.IsolationLevel.ISOLATION_LEVEL_UNSPECIFIED,
173
+ **kwargs,
174
+ ):
175
+ """Commit mutations to the database.
176
+
177
+ :type return_commit_stats: bool
178
+ :param return_commit_stats:
179
+ If true, the response will return commit stats which can be accessed though commit_stats.
180
+
181
+ :type request_options:
182
+ :class:`google.cloud.spanner_v1.types.RequestOptions`
183
+ :param request_options:
184
+ (Optional) Common options for this request.
185
+ If a dict is provided, it must be of the same form as the protobuf
186
+ message :class:`~google.cloud.spanner_v1.types.RequestOptions`.
187
+
188
+ :type max_commit_delay: :class:`datetime.timedelta`
189
+ :param max_commit_delay:
190
+ (Optional) The amount of latency this request is willing to incur
191
+ in order to improve throughput.
192
+
193
+ :type exclude_txn_from_change_streams: bool
194
+ :param exclude_txn_from_change_streams:
195
+ (Optional) If true, instructs the transaction to be excluded from being recorded in change streams
196
+ with the DDL option `allow_txn_exclusion=true`. This does not exclude the transaction from
197
+ being recorded in the change streams with the DDL option `allow_txn_exclusion` being false or
198
+ unset.
199
+
200
+ :type isolation_level:
201
+ :class:`google.cloud.spanner_v1.types.TransactionOptions.IsolationLevel`
202
+ :param isolation_level:
203
+ (Optional) Sets isolation level for the transaction.
204
+
205
+ :rtype: datetime
206
+ :returns: timestamp of the committed changes.
207
+ """
208
+ self._check_state()
209
+ database = self._session._database
210
+ api = database.spanner_api
211
+ metadata = _metadata_with_prefix(database.name)
212
+ if database._route_to_leader_enabled:
213
+ metadata.append(
214
+ _metadata_with_leader_aware_routing(database._route_to_leader_enabled)
215
+ )
216
+ txn_options = TransactionOptions(
217
+ read_write=TransactionOptions.ReadWrite(),
218
+ exclude_txn_from_change_streams=exclude_txn_from_change_streams,
219
+ isolation_level=isolation_level,
220
+ )
221
+
222
+ txn_options = _merge_Transaction_Options(
223
+ database.default_transaction_options.default_read_write_transaction_options,
224
+ txn_options,
225
+ )
226
+ trace_attributes = {"num_mutations": len(self._mutations)}
227
+
228
+ if request_options is None:
229
+ request_options = RequestOptions()
230
+ elif type(request_options) is dict:
231
+ request_options = RequestOptions(request_options)
232
+ request_options.transaction_tag = self.transaction_tag
233
+
234
+ # Request tags are not supported for commit requests.
235
+ request_options.request_tag = None
236
+
237
+ request = CommitRequest(
238
+ session=self._session.name,
239
+ mutations=self._mutations,
240
+ single_use_transaction=txn_options,
241
+ return_commit_stats=return_commit_stats,
242
+ max_commit_delay=max_commit_delay,
243
+ request_options=request_options,
244
+ )
245
+ observability_options = getattr(database, "observability_options", None)
246
+ with trace_call(
247
+ f"CloudSpanner.{type(self).__name__}.commit",
248
+ self._session,
249
+ trace_attributes,
250
+ observability_options=observability_options,
251
+ metadata=metadata,
252
+ ) as span, MetricsCapture():
253
+
254
+ def wrapped_method(*args, **kwargs):
255
+ method = functools.partial(
256
+ api.commit,
257
+ request=request,
258
+ metadata=database.metadata_with_request_id(
259
+ # This code is retried due to ABORTED, hence nth_request
260
+ # should be increased. attempt can only be increased if
261
+ # we encounter UNAVAILABLE or INTERNAL.
262
+ getattr(database, "_next_nth_request", 0),
263
+ 1,
264
+ metadata,
265
+ span,
266
+ ),
267
+ )
268
+ return method(*args, **kwargs)
269
+
270
+ deadline = time.time() + kwargs.get(
271
+ "timeout_secs", DEFAULT_RETRY_TIMEOUT_SECS
272
+ )
273
+ default_retry_delay = kwargs.get("default_retry_delay", None)
274
+ response = _retry_on_aborted_exception(
275
+ wrapped_method,
276
+ deadline=deadline,
277
+ default_retry_delay=default_retry_delay,
278
+ )
279
+ self.committed = response.commit_timestamp
280
+ self.commit_stats = response.commit_stats
281
+ return self.committed
282
+
283
+ def __enter__(self):
284
+ """Begin ``with`` block."""
285
+ self._check_state()
286
+
287
+ return self
288
+
289
+ def __exit__(self, exc_type, exc_val, exc_tb):
290
+ """End ``with`` block."""
291
+ if exc_type is None:
292
+ self.commit()
293
+
294
+
295
+ class MutationGroup(_BatchBase):
296
+ """A container for mutations.
297
+
298
+ Clients should use :class:`~google.cloud.spanner_v1.MutationGroups` to
299
+ obtain instances instead of directly creating instances.
300
+
301
+ :type session: :class:`~google.cloud.spanner_v1.session.Session`
302
+ :param session: The session used to perform the commit.
303
+
304
+ :type mutations: list
305
+ :param mutations: The list into which mutations are to be accumulated.
306
+ """
307
+
308
+ def __init__(self, session, mutations=[]):
309
+ super(MutationGroup, self).__init__(session)
310
+ self._mutations = mutations
311
+
312
+
313
+ class MutationGroups(_SessionWrapper):
314
+ """Accumulate mutation groups for transmission during :meth:`batch_write`.
315
+
316
+ :type session: :class:`~google.cloud.spanner_v1.session.Session`
317
+ :param session: the session used to perform the commit
318
+ """
319
+
320
+ committed = None
321
+
322
+ def __init__(self, session):
323
+ super(MutationGroups, self).__init__(session)
324
+ self._mutation_groups = []
325
+
326
+ def _check_state(self):
327
+ """Checks if the object's state is valid for making API requests.
328
+
329
+ :raises: :exc:`ValueError` if the object's state is invalid for making
330
+ API requests.
331
+ """
332
+ if self.committed is not None:
333
+ raise ValueError("MutationGroups already committed")
334
+
335
+ def group(self):
336
+ """Returns a new `MutationGroup` to which mutations can be added."""
337
+ mutation_group = BatchWriteRequest.MutationGroup()
338
+ self._mutation_groups.append(mutation_group)
339
+ return MutationGroup(self._session, mutation_group.mutations)
340
+
341
+ def batch_write(self, request_options=None, exclude_txn_from_change_streams=False):
342
+ """Executes batch_write.
343
+
344
+ :type request_options:
345
+ :class:`google.cloud.spanner_v1.types.RequestOptions`
346
+ :param request_options:
347
+ (Optional) Common options for this request.
348
+ If a dict is provided, it must be of the same form as the protobuf
349
+ message :class:`~google.cloud.spanner_v1.types.RequestOptions`.
350
+
351
+ :type exclude_txn_from_change_streams: bool
352
+ :param exclude_txn_from_change_streams:
353
+ (Optional) If true, instructs the transaction to be excluded from being recorded in change streams
354
+ with the DDL option `allow_txn_exclusion=true`. This does not exclude the transaction from
355
+ being recorded in the change streams with the DDL option `allow_txn_exclusion` being false or
356
+ unset.
357
+
358
+ :rtype: :class:`Iterable[google.cloud.spanner_v1.types.BatchWriteResponse]`
359
+ :returns: a sequence of responses for each batch.
360
+ """
361
+ self._check_state()
362
+
363
+ database = self._session._database
364
+ api = database.spanner_api
365
+ metadata = _metadata_with_prefix(database.name)
366
+ if database._route_to_leader_enabled:
367
+ metadata.append(
368
+ _metadata_with_leader_aware_routing(database._route_to_leader_enabled)
369
+ )
370
+ trace_attributes = {"num_mutation_groups": len(self._mutation_groups)}
371
+ if request_options is None:
372
+ request_options = RequestOptions()
373
+ elif type(request_options) is dict:
374
+ request_options = RequestOptions(request_options)
375
+
376
+ request = BatchWriteRequest(
377
+ session=self._session.name,
378
+ mutation_groups=self._mutation_groups,
379
+ request_options=request_options,
380
+ exclude_txn_from_change_streams=exclude_txn_from_change_streams,
381
+ )
382
+ observability_options = getattr(database, "observability_options", None)
383
+ with trace_call(
384
+ "CloudSpanner.batch_write",
385
+ self._session,
386
+ trace_attributes,
387
+ observability_options=observability_options,
388
+ metadata=metadata,
389
+ ) as span, MetricsCapture():
390
+ attempt = AtomicCounter(0)
391
+ nth_request = getattr(database, "_next_nth_request", 0)
392
+
393
+ def wrapped_method(*args, **kwargs):
394
+ method = functools.partial(
395
+ api.batch_write,
396
+ request=request,
397
+ metadata=database.metadata_with_request_id(
398
+ nth_request,
399
+ attempt.increment(),
400
+ metadata,
401
+ span,
402
+ ),
403
+ )
404
+ return method(*args, **kwargs)
405
+
406
+ response = _retry(
407
+ wrapped_method,
408
+ allowed_exceptions={
409
+ InternalServerError: _check_rst_stream_error,
410
+ },
411
+ )
412
+ self.committed = True
413
+ return response
414
+
415
+
416
+ def _make_write_pb(table, columns, values):
417
+ """Helper for :meth:`Batch.insert` et al.
418
+
419
+ :type table: str
420
+ :param table: Name of the table to be modified.
421
+
422
+ :type columns: list of str
423
+ :param columns: Name of the table columns to be modified.
424
+
425
+ :type values: list of lists
426
+ :param values: Values to be modified.
427
+
428
+ :rtype: :class:`google.cloud.spanner_v1.types.Mutation.Write`
429
+ :returns: Write protobuf
430
+ """
431
+ return Mutation.Write(
432
+ table=table, columns=columns, values=_make_list_value_pbs(values)
433
+ )