sqlalchemy-spanner 1.6.2__tar.gz → 1.8.0__tar.gz
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.
- {sqlalchemy-spanner-1.6.2/sqlalchemy_spanner.egg-info → sqlalchemy_spanner-1.8.0}/PKG-INFO +39 -17
- sqlalchemy-spanner-1.6.2/PKG-INFO → sqlalchemy_spanner-1.8.0/README.rst +31 -26
- {sqlalchemy-spanner-1.6.2 → sqlalchemy_spanner-1.8.0}/google/cloud/sqlalchemy_spanner/_opentelemetry_tracing.py +13 -0
- sqlalchemy_spanner-1.8.0/google/cloud/sqlalchemy_spanner/dml.py +26 -0
- {sqlalchemy-spanner-1.6.2 → sqlalchemy_spanner-1.8.0}/google/cloud/sqlalchemy_spanner/requirements.py +1 -1
- {sqlalchemy-spanner-1.6.2 → sqlalchemy_spanner-1.8.0}/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +235 -26
- {sqlalchemy-spanner-1.6.2 → sqlalchemy_spanner-1.8.0}/setup.py +25 -21
- sqlalchemy-spanner-1.6.2/README.rst → sqlalchemy_spanner-1.8.0/sqlalchemy_spanner.egg-info/PKG-INFO +48 -15
- {sqlalchemy-spanner-1.6.2 → sqlalchemy_spanner-1.8.0}/sqlalchemy_spanner.egg-info/SOURCES.txt +1 -0
- {sqlalchemy-spanner-1.6.2 → sqlalchemy_spanner-1.8.0}/test/test_suite_13.py +172 -1
- {sqlalchemy-spanner-1.6.2 → sqlalchemy_spanner-1.8.0}/test/test_suite_14.py +183 -2
- {sqlalchemy-spanner-1.6.2 → sqlalchemy_spanner-1.8.0}/test/test_suite_20.py +296 -20
- {sqlalchemy-spanner-1.6.2 → sqlalchemy_spanner-1.8.0}/LICENSE +0 -0
- {sqlalchemy-spanner-1.6.2 → sqlalchemy_spanner-1.8.0}/google/__init__.py +0 -0
- {sqlalchemy-spanner-1.6.2 → sqlalchemy_spanner-1.8.0}/google/cloud/__init__.py +0 -0
- {sqlalchemy-spanner-1.6.2 → sqlalchemy_spanner-1.8.0}/google/cloud/sqlalchemy_spanner/__init__.py +0 -0
- {sqlalchemy-spanner-1.6.2 → sqlalchemy_spanner-1.8.0}/google/cloud/sqlalchemy_spanner/provision.py +0 -0
- {sqlalchemy-spanner-1.6.2 → sqlalchemy_spanner-1.8.0}/setup.cfg +0 -0
- {sqlalchemy-spanner-1.6.2 → sqlalchemy_spanner-1.8.0}/sqlalchemy_spanner.egg-info/dependency_links.txt +0 -0
- {sqlalchemy-spanner-1.6.2 → sqlalchemy_spanner-1.8.0}/sqlalchemy_spanner.egg-info/entry_points.txt +0 -0
- {sqlalchemy-spanner-1.6.2 → sqlalchemy_spanner-1.8.0}/sqlalchemy_spanner.egg-info/namespace_packages.txt +0 -0
- {sqlalchemy-spanner-1.6.2 → sqlalchemy_spanner-1.8.0}/sqlalchemy_spanner.egg-info/not-zip-safe +0 -0
- {sqlalchemy-spanner-1.6.2 → sqlalchemy_spanner-1.8.0}/sqlalchemy_spanner.egg-info/requires.txt +0 -0
- {sqlalchemy-spanner-1.6.2 → sqlalchemy_spanner-1.8.0}/sqlalchemy_spanner.egg-info/top_level.txt +0 -0
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sqlalchemy-spanner
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.8.0
|
|
4
4
|
Summary: SQLAlchemy dialect integrated into Cloud Spanner database
|
|
5
5
|
Home-page: https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy
|
|
6
6
|
Author: Google LLC
|
|
7
7
|
Author-email: cloud-spanner-developers@googlegroups.com
|
|
8
8
|
Classifier: Intended Audience :: Developers
|
|
9
|
-
Provides-Extra: tracing
|
|
10
9
|
License-File: LICENSE
|
|
10
|
+
Requires-Dist: sqlalchemy>=1.1.13
|
|
11
|
+
Requires-Dist: google-cloud-spanner>=3.12.0
|
|
12
|
+
Requires-Dist: alembic
|
|
13
|
+
Provides-Extra: tracing
|
|
14
|
+
Requires-Dist: opentelemetry-api>=1.1.0; extra == "tracing"
|
|
15
|
+
Requires-Dist: opentelemetry-sdk>=1.1.0; extra == "tracing"
|
|
16
|
+
Requires-Dist: opentelemetry-instrumentation>=0.20b0; extra == "tracing"
|
|
11
17
|
|
|
12
18
|
Spanner dialect for SQLAlchemy
|
|
13
19
|
==============================
|
|
@@ -69,6 +75,13 @@ Next install the package from the package ``setup.py`` file:
|
|
|
69
75
|
|
|
70
76
|
During setup the dialect will be registered with entry points.
|
|
71
77
|
|
|
78
|
+
Samples
|
|
79
|
+
-------------
|
|
80
|
+
|
|
81
|
+
The `samples directory <https://github.com/googleapis/python-spanner-sqlalchemy/blob/-/samples/README.md>`__
|
|
82
|
+
contains multiple examples for how to configure and use common Spanner features.
|
|
83
|
+
|
|
84
|
+
|
|
72
85
|
A Minimal App
|
|
73
86
|
-------------
|
|
74
87
|
|
|
@@ -84,7 +97,7 @@ on this step in a dialect prefix part:
|
|
|
84
97
|
# for SQLAlchemy 1.3:
|
|
85
98
|
spanner:///projects/project-id/instances/instance-id/databases/database-id
|
|
86
99
|
|
|
87
|
-
# for SQLAlchemy 1.4:
|
|
100
|
+
# for SQLAlchemy 1.4 and 2.0:
|
|
88
101
|
spanner+spanner:///projects/project-id/instances/instance-id/databases/database-id
|
|
89
102
|
|
|
90
103
|
To pass your custom client object directly to be be used, create engine as following:
|
|
@@ -241,7 +254,7 @@ Unique constraints
|
|
|
241
254
|
~~~~~~~~~~~~~~~~~~
|
|
242
255
|
|
|
243
256
|
Cloud Spanner doesn't support direct UNIQUE constraints creation. In
|
|
244
|
-
order to achieve column values uniqueness UNIQUE indexes should be used.
|
|
257
|
+
order to achieve column values uniqueness, UNIQUE indexes should be used.
|
|
245
258
|
|
|
246
259
|
Instead of direct UNIQUE constraint creation:
|
|
247
260
|
|
|
@@ -269,10 +282,16 @@ Autocommit mode
|
|
|
269
282
|
~~~~~~~~~~~~~~~
|
|
270
283
|
|
|
271
284
|
Spanner dialect supports both ``SERIALIZABLE`` and ``AUTOCOMMIT``
|
|
272
|
-
isolation levels. ``SERIALIZABLE`` is the default
|
|
273
|
-
|
|
274
|
-
corresponds to automatically committing
|
|
275
|
-
|
|
285
|
+
isolation levels. ``SERIALIZABLE`` is the default isolation level.
|
|
286
|
+
|
|
287
|
+
``AUTOCOMMIT`` mode corresponds to automatically committing each
|
|
288
|
+
insert/update/delete statement right after is has been executed.
|
|
289
|
+
Queries that are executed in ``AUTOCOMMIT`` mode use a single-use
|
|
290
|
+
read-only transaction. These do not take any locks and do not need
|
|
291
|
+
to be committed.
|
|
292
|
+
|
|
293
|
+
Workloads that only read data, should use either ``AUTOCOMMIT`` or
|
|
294
|
+
a read-only transaction.
|
|
276
295
|
|
|
277
296
|
Isolation level change example:
|
|
278
297
|
|
|
@@ -283,7 +302,7 @@ Isolation level change example:
|
|
|
283
302
|
eng = create_engine("spanner:///projects/project-id/instances/instance-id/databases/database-id")
|
|
284
303
|
autocommit_engine = eng.execution_options(isolation_level="AUTOCOMMIT")
|
|
285
304
|
|
|
286
|
-
Automatic
|
|
305
|
+
Automatic transaction retry
|
|
287
306
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
288
307
|
In the default ``SERIALIZABLE`` mode transactions may fail with ``Aborted`` exception. This is a transient kind of errors, which mostly happen to prevent data corruption by concurrent modifications. Though the original transaction becomes non operational, a simple retry of the queries solves the issue.
|
|
289
308
|
|
|
@@ -291,8 +310,8 @@ This, however, may require to manually repeat a long list of operations, execute
|
|
|
291
310
|
|
|
292
311
|
In ``AUTOCOMMIT`` mode automatic transactions retry mechanism is disabled, as every operation is committed just in time, and there is no way an ``Aborted`` exception can happen.
|
|
293
312
|
|
|
294
|
-
|
|
295
|
-
|
|
313
|
+
Auto-incremented IDs
|
|
314
|
+
~~~~~~~~~~~~~~~~~~~~
|
|
296
315
|
|
|
297
316
|
Cloud Spanner doesn't support autoincremented IDs mechanism due to
|
|
298
317
|
performance reasons (`see for more
|
|
@@ -348,8 +367,9 @@ ReadOnly transactions
|
|
|
348
367
|
~~~~~~~~~~~~~~~~~~~~~
|
|
349
368
|
|
|
350
369
|
By default, transactions produced by a Spanner connection are in
|
|
351
|
-
ReadWrite mode. However,
|
|
352
|
-
|
|
370
|
+
ReadWrite mode. However, workloads that only read data perform better
|
|
371
|
+
if they use read-only transactions, as Spanner does not need to take
|
|
372
|
+
locks for the data that is read; for these cases, the Spanner dialect
|
|
353
373
|
supports the ``read_only`` execution option, which switches a connection
|
|
354
374
|
into ReadOnly mode:
|
|
355
375
|
|
|
@@ -358,11 +378,13 @@ into ReadOnly mode:
|
|
|
358
378
|
with engine.connect().execution_options(read_only=True) as connection:
|
|
359
379
|
connection.execute(select(["*"], from_obj=table)).fetchall()
|
|
360
380
|
|
|
361
|
-
|
|
362
|
-
|
|
381
|
+
See the `Read-only transaction sample
|
|
382
|
+
<https://github.com/googleapis/python-spanner-sqlalchemy/blob/-/samples/read_only_transaction_sample.py>`__
|
|
383
|
+
for a concrete example.
|
|
363
384
|
|
|
364
385
|
ReadOnly/ReadWrite mode of a connection can't be changed while a
|
|
365
|
-
transaction is in progress -
|
|
386
|
+
transaction is in progress - you must commit or rollback the current
|
|
387
|
+
transaction before changing the mode.
|
|
366
388
|
|
|
367
389
|
Stale reads
|
|
368
390
|
~~~~~~~~~~~
|
|
@@ -519,7 +541,7 @@ run the tests the ``nox`` package commands can be used:
|
|
|
519
541
|
Running tests on Spanner emulator
|
|
520
542
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
521
543
|
|
|
522
|
-
The dialect test suite can be
|
|
544
|
+
The dialect test suite can be run on `Spanner
|
|
523
545
|
emulator <https://cloud.google.com/spanner/docs/emulator>`__. Several
|
|
524
546
|
tests, relating to ``NULL`` values of data types, are skipped when
|
|
525
547
|
executed on emulator.
|
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: sqlalchemy-spanner
|
|
3
|
-
Version: 1.6.2
|
|
4
|
-
Summary: SQLAlchemy dialect integrated into Cloud Spanner database
|
|
5
|
-
Home-page: https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy
|
|
6
|
-
Author: Google LLC
|
|
7
|
-
Author-email: cloud-spanner-developers@googlegroups.com
|
|
8
|
-
Classifier: Intended Audience :: Developers
|
|
9
|
-
Provides-Extra: tracing
|
|
10
|
-
License-File: LICENSE
|
|
11
|
-
|
|
12
1
|
Spanner dialect for SQLAlchemy
|
|
13
2
|
==============================
|
|
14
3
|
|
|
@@ -69,6 +58,13 @@ Next install the package from the package ``setup.py`` file:
|
|
|
69
58
|
|
|
70
59
|
During setup the dialect will be registered with entry points.
|
|
71
60
|
|
|
61
|
+
Samples
|
|
62
|
+
-------------
|
|
63
|
+
|
|
64
|
+
The `samples directory <https://github.com/googleapis/python-spanner-sqlalchemy/blob/-/samples/README.md>`__
|
|
65
|
+
contains multiple examples for how to configure and use common Spanner features.
|
|
66
|
+
|
|
67
|
+
|
|
72
68
|
A Minimal App
|
|
73
69
|
-------------
|
|
74
70
|
|
|
@@ -84,7 +80,7 @@ on this step in a dialect prefix part:
|
|
|
84
80
|
# for SQLAlchemy 1.3:
|
|
85
81
|
spanner:///projects/project-id/instances/instance-id/databases/database-id
|
|
86
82
|
|
|
87
|
-
# for SQLAlchemy 1.4:
|
|
83
|
+
# for SQLAlchemy 1.4 and 2.0:
|
|
88
84
|
spanner+spanner:///projects/project-id/instances/instance-id/databases/database-id
|
|
89
85
|
|
|
90
86
|
To pass your custom client object directly to be be used, create engine as following:
|
|
@@ -241,7 +237,7 @@ Unique constraints
|
|
|
241
237
|
~~~~~~~~~~~~~~~~~~
|
|
242
238
|
|
|
243
239
|
Cloud Spanner doesn't support direct UNIQUE constraints creation. In
|
|
244
|
-
order to achieve column values uniqueness UNIQUE indexes should be used.
|
|
240
|
+
order to achieve column values uniqueness, UNIQUE indexes should be used.
|
|
245
241
|
|
|
246
242
|
Instead of direct UNIQUE constraint creation:
|
|
247
243
|
|
|
@@ -269,10 +265,16 @@ Autocommit mode
|
|
|
269
265
|
~~~~~~~~~~~~~~~
|
|
270
266
|
|
|
271
267
|
Spanner dialect supports both ``SERIALIZABLE`` and ``AUTOCOMMIT``
|
|
272
|
-
isolation levels. ``SERIALIZABLE`` is the default
|
|
273
|
-
|
|
274
|
-
corresponds to automatically committing
|
|
275
|
-
|
|
268
|
+
isolation levels. ``SERIALIZABLE`` is the default isolation level.
|
|
269
|
+
|
|
270
|
+
``AUTOCOMMIT`` mode corresponds to automatically committing each
|
|
271
|
+
insert/update/delete statement right after is has been executed.
|
|
272
|
+
Queries that are executed in ``AUTOCOMMIT`` mode use a single-use
|
|
273
|
+
read-only transaction. These do not take any locks and do not need
|
|
274
|
+
to be committed.
|
|
275
|
+
|
|
276
|
+
Workloads that only read data, should use either ``AUTOCOMMIT`` or
|
|
277
|
+
a read-only transaction.
|
|
276
278
|
|
|
277
279
|
Isolation level change example:
|
|
278
280
|
|
|
@@ -283,7 +285,7 @@ Isolation level change example:
|
|
|
283
285
|
eng = create_engine("spanner:///projects/project-id/instances/instance-id/databases/database-id")
|
|
284
286
|
autocommit_engine = eng.execution_options(isolation_level="AUTOCOMMIT")
|
|
285
287
|
|
|
286
|
-
Automatic
|
|
288
|
+
Automatic transaction retry
|
|
287
289
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
288
290
|
In the default ``SERIALIZABLE`` mode transactions may fail with ``Aborted`` exception. This is a transient kind of errors, which mostly happen to prevent data corruption by concurrent modifications. Though the original transaction becomes non operational, a simple retry of the queries solves the issue.
|
|
289
291
|
|
|
@@ -291,8 +293,8 @@ This, however, may require to manually repeat a long list of operations, execute
|
|
|
291
293
|
|
|
292
294
|
In ``AUTOCOMMIT`` mode automatic transactions retry mechanism is disabled, as every operation is committed just in time, and there is no way an ``Aborted`` exception can happen.
|
|
293
295
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
+
Auto-incremented IDs
|
|
297
|
+
~~~~~~~~~~~~~~~~~~~~
|
|
296
298
|
|
|
297
299
|
Cloud Spanner doesn't support autoincremented IDs mechanism due to
|
|
298
300
|
performance reasons (`see for more
|
|
@@ -348,8 +350,9 @@ ReadOnly transactions
|
|
|
348
350
|
~~~~~~~~~~~~~~~~~~~~~
|
|
349
351
|
|
|
350
352
|
By default, transactions produced by a Spanner connection are in
|
|
351
|
-
ReadWrite mode. However,
|
|
352
|
-
|
|
353
|
+
ReadWrite mode. However, workloads that only read data perform better
|
|
354
|
+
if they use read-only transactions, as Spanner does not need to take
|
|
355
|
+
locks for the data that is read; for these cases, the Spanner dialect
|
|
353
356
|
supports the ``read_only`` execution option, which switches a connection
|
|
354
357
|
into ReadOnly mode:
|
|
355
358
|
|
|
@@ -358,11 +361,13 @@ into ReadOnly mode:
|
|
|
358
361
|
with engine.connect().execution_options(read_only=True) as connection:
|
|
359
362
|
connection.execute(select(["*"], from_obj=table)).fetchall()
|
|
360
363
|
|
|
361
|
-
|
|
362
|
-
|
|
364
|
+
See the `Read-only transaction sample
|
|
365
|
+
<https://github.com/googleapis/python-spanner-sqlalchemy/blob/-/samples/read_only_transaction_sample.py>`__
|
|
366
|
+
for a concrete example.
|
|
363
367
|
|
|
364
368
|
ReadOnly/ReadWrite mode of a connection can't be changed while a
|
|
365
|
-
transaction is in progress -
|
|
369
|
+
transaction is in progress - you must commit or rollback the current
|
|
370
|
+
transaction before changing the mode.
|
|
366
371
|
|
|
367
372
|
Stale reads
|
|
368
373
|
~~~~~~~~~~~
|
|
@@ -519,7 +524,7 @@ run the tests the ``nox`` package commands can be used:
|
|
|
519
524
|
Running tests on Spanner emulator
|
|
520
525
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
521
526
|
|
|
522
|
-
The dialect test suite can be
|
|
527
|
+
The dialect test suite can be run on `Spanner
|
|
523
528
|
emulator <https://cloud.google.com/spanner/docs/emulator>`__. Several
|
|
524
529
|
tests, relating to ``NULL`` values of data types, are skipped when
|
|
525
530
|
executed on emulator.
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
|
|
15
15
|
"""Manages OpenTelemetry trace creation and handling"""
|
|
16
16
|
|
|
17
|
+
import collections
|
|
18
|
+
import os
|
|
19
|
+
|
|
17
20
|
from contextlib import contextmanager
|
|
18
21
|
|
|
19
22
|
from google.api_core.exceptions import GoogleAPICallError
|
|
@@ -46,6 +49,16 @@ def trace_call(name, extra_attributes=None):
|
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
if extra_attributes:
|
|
52
|
+
if os.environ.get("SQLALCHEMY_SPANNER_TRACE_HIDE_QUERY_PARAMETERS"):
|
|
53
|
+
extra_attributes.pop("db.params", None)
|
|
54
|
+
|
|
55
|
+
# Stringify "db.params" sequence values before sending to OpenTelemetry,
|
|
56
|
+
# otherwise OpenTelemetry may log a Warning if types differ.
|
|
57
|
+
if isinstance(extra_attributes, dict):
|
|
58
|
+
for k, v in extra_attributes.items():
|
|
59
|
+
if k == "db.params" and isinstance(v, collections.abc.Sequence):
|
|
60
|
+
extra_attributes[k] = [str(e) for e in v]
|
|
61
|
+
|
|
49
62
|
attributes.update(extra_attributes)
|
|
50
63
|
|
|
51
64
|
with tracer.start_as_current_span(
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Copyright 2024 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
|
+
from sqlalchemy import Insert, insert
|
|
16
|
+
from sqlalchemy.sql._typing import _DMLTableArgument
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def insert_or_update(table: _DMLTableArgument) -> Insert:
|
|
20
|
+
"""Construct a Spanner-specific insert-or-update statement."""
|
|
21
|
+
return insert(table).prefix_with("OR UPDATE")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def insert_or_ignore(table: _DMLTableArgument) -> Insert:
|
|
25
|
+
"""Construct a Spanner-specific insert-or-ignore statement."""
|
|
26
|
+
return insert(table).prefix_with("OR IGNORE")
|